@elizaos/autonomous 2.0.0-alpha.10

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 (241) hide show
  1. package/LICENSE +21 -0
  2. package/package.json +270 -0
  3. package/src/actions/emote.ts +101 -0
  4. package/src/actions/restart.ts +101 -0
  5. package/src/actions/send-message.ts +168 -0
  6. package/src/actions/stream-control.ts +439 -0
  7. package/src/actions/switch-stream-source.ts +126 -0
  8. package/src/actions/terminal.ts +186 -0
  9. package/src/api/agent-admin-routes.ts +178 -0
  10. package/src/api/agent-lifecycle-routes.ts +129 -0
  11. package/src/api/agent-model.ts +143 -0
  12. package/src/api/agent-transfer-routes.ts +211 -0
  13. package/src/api/apps-routes.ts +210 -0
  14. package/src/api/auth-routes.ts +90 -0
  15. package/src/api/bsc-trade.ts +736 -0
  16. package/src/api/bug-report-routes.ts +161 -0
  17. package/src/api/character-routes.ts +421 -0
  18. package/src/api/cloud-billing-routes.ts +598 -0
  19. package/src/api/cloud-compat-routes.ts +192 -0
  20. package/src/api/cloud-routes.ts +529 -0
  21. package/src/api/cloud-status-routes.ts +234 -0
  22. package/src/api/compat-utils.ts +154 -0
  23. package/src/api/connector-health.ts +135 -0
  24. package/src/api/coordinator-wiring.ts +179 -0
  25. package/src/api/credit-detection.ts +47 -0
  26. package/src/api/database.ts +1357 -0
  27. package/src/api/diagnostics-routes.ts +389 -0
  28. package/src/api/drop-service.ts +205 -0
  29. package/src/api/early-logs.ts +111 -0
  30. package/src/api/http-helpers.ts +252 -0
  31. package/src/api/index.ts +85 -0
  32. package/src/api/knowledge-routes.ts +1189 -0
  33. package/src/api/knowledge-service-loader.ts +92 -0
  34. package/src/api/memory-bounds.ts +121 -0
  35. package/src/api/memory-routes.ts +349 -0
  36. package/src/api/merkle-tree.ts +239 -0
  37. package/src/api/models-routes.ts +72 -0
  38. package/src/api/nfa-routes.ts +169 -0
  39. package/src/api/nft-verify.ts +188 -0
  40. package/src/api/og-tracker.ts +72 -0
  41. package/src/api/parse-action-block.ts +145 -0
  42. package/src/api/permissions-routes.ts +222 -0
  43. package/src/api/plugin-validation.ts +355 -0
  44. package/src/api/provider-switch-config.ts +455 -0
  45. package/src/api/registry-routes.ts +165 -0
  46. package/src/api/registry-service.ts +292 -0
  47. package/src/api/route-helpers.ts +21 -0
  48. package/src/api/sandbox-routes.ts +1480 -0
  49. package/src/api/server.ts +17674 -0
  50. package/src/api/signal-routes.ts +265 -0
  51. package/src/api/stream-persistence.ts +297 -0
  52. package/src/api/stream-route-state.ts +48 -0
  53. package/src/api/stream-routes.ts +1046 -0
  54. package/src/api/stream-voice-routes.ts +208 -0
  55. package/src/api/streaming-text.ts +129 -0
  56. package/src/api/streaming-types.ts +23 -0
  57. package/src/api/subscription-routes.ts +283 -0
  58. package/src/api/terminal-run-limits.ts +31 -0
  59. package/src/api/training-backend-check.ts +40 -0
  60. package/src/api/training-routes.ts +314 -0
  61. package/src/api/training-service-like.ts +46 -0
  62. package/src/api/trajectory-routes.ts +714 -0
  63. package/src/api/trigger-routes.ts +438 -0
  64. package/src/api/twitter-verify.ts +226 -0
  65. package/src/api/tx-service.ts +193 -0
  66. package/src/api/wallet-dex-prices.ts +206 -0
  67. package/src/api/wallet-evm-balance.ts +989 -0
  68. package/src/api/wallet-routes.ts +505 -0
  69. package/src/api/wallet-rpc.ts +523 -0
  70. package/src/api/wallet-trading-profile.ts +694 -0
  71. package/src/api/wallet.ts +745 -0
  72. package/src/api/whatsapp-routes.ts +282 -0
  73. package/src/api/zip-utils.ts +130 -0
  74. package/src/auth/anthropic.ts +63 -0
  75. package/src/auth/apply-stealth.ts +38 -0
  76. package/src/auth/claude-code-stealth.ts +141 -0
  77. package/src/auth/credentials.ts +226 -0
  78. package/src/auth/index.ts +18 -0
  79. package/src/auth/openai-codex.ts +94 -0
  80. package/src/auth/types.ts +24 -0
  81. package/src/awareness/registry.ts +220 -0
  82. package/src/bin.ts +10 -0
  83. package/src/cli/index.ts +36 -0
  84. package/src/cli/parse-duration.ts +43 -0
  85. package/src/cloud/auth.test.ts +370 -0
  86. package/src/cloud/auth.ts +176 -0
  87. package/src/cloud/backup.test.ts +150 -0
  88. package/src/cloud/backup.ts +50 -0
  89. package/src/cloud/base-url.ts +45 -0
  90. package/src/cloud/bridge-client.test.ts +481 -0
  91. package/src/cloud/bridge-client.ts +307 -0
  92. package/src/cloud/cloud-manager.test.ts +223 -0
  93. package/src/cloud/cloud-manager.ts +151 -0
  94. package/src/cloud/cloud-proxy.test.ts +122 -0
  95. package/src/cloud/cloud-proxy.ts +52 -0
  96. package/src/cloud/index.ts +23 -0
  97. package/src/cloud/reconnect.test.ts +178 -0
  98. package/src/cloud/reconnect.ts +108 -0
  99. package/src/cloud/validate-url.test.ts +147 -0
  100. package/src/cloud/validate-url.ts +176 -0
  101. package/src/config/character-schema.ts +44 -0
  102. package/src/config/config.ts +149 -0
  103. package/src/config/env-vars.ts +86 -0
  104. package/src/config/includes.ts +196 -0
  105. package/src/config/index.ts +15 -0
  106. package/src/config/object-utils.ts +10 -0
  107. package/src/config/paths.ts +92 -0
  108. package/src/config/plugin-auto-enable.ts +520 -0
  109. package/src/config/schema.ts +1342 -0
  110. package/src/config/telegram-custom-commands.ts +99 -0
  111. package/src/config/types.agent-defaults.ts +342 -0
  112. package/src/config/types.agents.ts +112 -0
  113. package/src/config/types.gateway.ts +243 -0
  114. package/src/config/types.hooks.ts +124 -0
  115. package/src/config/types.messages.ts +201 -0
  116. package/src/config/types.milady.ts +791 -0
  117. package/src/config/types.tools.ts +416 -0
  118. package/src/config/types.ts +7 -0
  119. package/src/config/zod-schema.agent-runtime.ts +777 -0
  120. package/src/config/zod-schema.core.ts +778 -0
  121. package/src/config/zod-schema.hooks.ts +139 -0
  122. package/src/config/zod-schema.providers-core.ts +1126 -0
  123. package/src/config/zod-schema.session.ts +98 -0
  124. package/src/config/zod-schema.ts +865 -0
  125. package/src/contracts/apps.ts +46 -0
  126. package/src/contracts/awareness.ts +56 -0
  127. package/src/contracts/config.ts +172 -0
  128. package/src/contracts/drop.ts +21 -0
  129. package/src/contracts/index.ts +8 -0
  130. package/src/contracts/onboarding.ts +592 -0
  131. package/src/contracts/permissions.ts +52 -0
  132. package/src/contracts/verification.ts +9 -0
  133. package/src/contracts/wallet.ts +503 -0
  134. package/src/diagnostics/integration-observability.ts +132 -0
  135. package/src/emotes/catalog.ts +655 -0
  136. package/src/external-modules.d.ts +7 -0
  137. package/src/hooks/discovery.test.ts +357 -0
  138. package/src/hooks/discovery.ts +231 -0
  139. package/src/hooks/eligibility.ts +146 -0
  140. package/src/hooks/hooks.test.ts +320 -0
  141. package/src/hooks/index.ts +8 -0
  142. package/src/hooks/loader.test.ts +418 -0
  143. package/src/hooks/loader.ts +256 -0
  144. package/src/hooks/registry.test.ts +168 -0
  145. package/src/hooks/registry.ts +74 -0
  146. package/src/hooks/types.ts +121 -0
  147. package/src/index.ts +19 -0
  148. package/src/onboarding-presets.ts +828 -0
  149. package/src/plugins/custom-rtmp/index.ts +40 -0
  150. package/src/providers/admin-trust.ts +76 -0
  151. package/src/providers/session-bridge.ts +143 -0
  152. package/src/providers/session-utils.ts +42 -0
  153. package/src/providers/simple-mode.ts +113 -0
  154. package/src/providers/ui-catalog.ts +135 -0
  155. package/src/providers/workspace-provider.ts +213 -0
  156. package/src/providers/workspace.ts +497 -0
  157. package/src/runtime/agent-event-service.ts +57 -0
  158. package/src/runtime/cloud-onboarding.test.ts +489 -0
  159. package/src/runtime/cloud-onboarding.ts +408 -0
  160. package/src/runtime/core-plugins.ts +53 -0
  161. package/src/runtime/custom-actions.ts +605 -0
  162. package/src/runtime/eliza.ts +4941 -0
  163. package/src/runtime/embedding-presets.ts +73 -0
  164. package/src/runtime/index.ts +8 -0
  165. package/src/runtime/milady-plugin.ts +180 -0
  166. package/src/runtime/onboarding-names.ts +76 -0
  167. package/src/runtime/release-plugin-policy.ts +119 -0
  168. package/src/runtime/restart.ts +59 -0
  169. package/src/runtime/trajectory-persistence.ts +2584 -0
  170. package/src/runtime/version.ts +6 -0
  171. package/src/security/audit-log.ts +222 -0
  172. package/src/security/network-policy.ts +91 -0
  173. package/src/server/index.ts +6 -0
  174. package/src/services/agent-export.ts +976 -0
  175. package/src/services/app-manager.ts +755 -0
  176. package/src/services/browser-capture.ts +215 -0
  177. package/src/services/coding-agent-context.ts +355 -0
  178. package/src/services/fallback-training-service.ts +196 -0
  179. package/src/services/index.ts +17 -0
  180. package/src/services/mcp-marketplace.ts +327 -0
  181. package/src/services/plugin-manager-types.ts +185 -0
  182. package/src/services/privy-wallets.ts +352 -0
  183. package/src/services/registry-client-app-meta.ts +201 -0
  184. package/src/services/registry-client-endpoints.ts +253 -0
  185. package/src/services/registry-client-local.ts +485 -0
  186. package/src/services/registry-client-network.ts +173 -0
  187. package/src/services/registry-client-queries.ts +176 -0
  188. package/src/services/registry-client-types.ts +104 -0
  189. package/src/services/registry-client.ts +366 -0
  190. package/src/services/remote-signing-service.ts +261 -0
  191. package/src/services/sandbox-engine.ts +753 -0
  192. package/src/services/sandbox-manager.ts +503 -0
  193. package/src/services/self-updater.ts +213 -0
  194. package/src/services/signal-pairing.ts +189 -0
  195. package/src/services/signing-policy.ts +230 -0
  196. package/src/services/skill-catalog-client.ts +195 -0
  197. package/src/services/skill-marketplace.ts +909 -0
  198. package/src/services/stream-manager.ts +707 -0
  199. package/src/services/tts-stream-bridge.ts +465 -0
  200. package/src/services/update-checker.ts +163 -0
  201. package/src/services/version-compat.ts +367 -0
  202. package/src/services/whatsapp-pairing.ts +279 -0
  203. package/src/shared/ui-catalog-prompt.ts +1158 -0
  204. package/src/test-support/process-helpers.ts +35 -0
  205. package/src/test-support/route-test-helpers.ts +113 -0
  206. package/src/test-support/test-helpers.ts +304 -0
  207. package/src/testing/index.ts +3 -0
  208. package/src/triggers/action.ts +342 -0
  209. package/src/triggers/runtime.ts +432 -0
  210. package/src/triggers/scheduling.ts +472 -0
  211. package/src/triggers/types.ts +133 -0
  212. package/src/types/app-hyperscape-routes-shim.d.ts +29 -0
  213. package/src/types/external-modules.d.ts +7 -0
  214. package/src/utils/exec-safety.ts +23 -0
  215. package/src/utils/number-parsing.ts +112 -0
  216. package/src/utils/spoken-text.ts +65 -0
  217. package/src/version-resolver.ts +60 -0
  218. package/test/api/agent-admin-routes.test.ts +160 -0
  219. package/test/api/agent-lifecycle-routes.test.ts +164 -0
  220. package/test/api/agent-transfer-routes.test.ts +136 -0
  221. package/test/api/apps-routes.test.ts +140 -0
  222. package/test/api/auth-routes.test.ts +160 -0
  223. package/test/api/bug-report-routes.test.ts +88 -0
  224. package/test/api/knowledge-routes.test.ts +73 -0
  225. package/test/api/lifecycle.test.ts +342 -0
  226. package/test/api/memory-routes.test.ts +74 -0
  227. package/test/api/models-routes.test.ts +112 -0
  228. package/test/api/nfa-routes.test.ts +78 -0
  229. package/test/api/permissions-routes.test.ts +185 -0
  230. package/test/api/registry-routes.test.ts +157 -0
  231. package/test/api/signal-routes.test.ts +113 -0
  232. package/test/api/subscription-routes.test.ts +90 -0
  233. package/test/api/trigger-routes.test.ts +87 -0
  234. package/test/api/wallet-routes.observability.test.ts +191 -0
  235. package/test/api/wallet-routes.test.ts +502 -0
  236. package/test/diagnostics/integration-observability.test.ts +135 -0
  237. package/test/security/audit-log.test.ts +229 -0
  238. package/test/security/network-policy.test.ts +143 -0
  239. package/test/services/version-compat.test.ts +127 -0
  240. package/tsconfig.build.json +21 -0
  241. package/tsconfig.json +19 -0
@@ -0,0 +1,57 @@
1
+ import type { UUID } from "@elizaos/core";
2
+
3
+ export interface AgentEventPayloadLike {
4
+ runId: string;
5
+ seq: number;
6
+ stream: string;
7
+ ts: number;
8
+ data: Record<string, unknown>;
9
+ sessionKey?: string;
10
+ agentId?: string;
11
+ roomId?: UUID;
12
+ }
13
+
14
+ export interface HeartbeatEventPayloadLike {
15
+ ts: number;
16
+ status: string;
17
+ to?: string;
18
+ preview?: string;
19
+ durationMs?: number;
20
+ hasMedia?: boolean;
21
+ reason?: string;
22
+ channel?: string;
23
+ silent?: boolean;
24
+ indicatorType?: string;
25
+ }
26
+
27
+ export interface AgentEventServiceLike {
28
+ subscribe: (listener: (event: AgentEventPayloadLike) => void) => () => void;
29
+ subscribeHeartbeat: (
30
+ listener: (event: HeartbeatEventPayloadLike) => void,
31
+ ) => () => void;
32
+ getLastHeartbeat?: () => HeartbeatEventPayloadLike | null;
33
+ }
34
+
35
+ type RuntimeWithServiceGetter = {
36
+ getService: (serviceType: string) => unknown | null;
37
+ };
38
+
39
+ export const AGENT_EVENT_SERVICE_TYPES = [
40
+ "agent_event",
41
+ "AGENT_EVENT",
42
+ ] as const;
43
+
44
+ export function getAgentEventService(
45
+ runtime: RuntimeWithServiceGetter | null | undefined,
46
+ ): AgentEventServiceLike | null {
47
+ if (!runtime) return null;
48
+
49
+ for (const serviceType of AGENT_EVENT_SERVICE_TYPES) {
50
+ const service = runtime.getService(serviceType);
51
+ if (service) {
52
+ return service as AgentEventServiceLike;
53
+ }
54
+ }
55
+
56
+ return null;
57
+ }
@@ -0,0 +1,489 @@
1
+ /**
2
+ * Tests for cloud-onboarding.ts
3
+ *
4
+ * Mocks fetch, @clack/prompts, and the cloud auth/bridge modules to verify
5
+ * the orchestration logic without requiring a live Eliza Cloud instance.
6
+ */
7
+
8
+ import {
9
+ afterEach,
10
+ assert,
11
+ beforeEach,
12
+ describe,
13
+ expect,
14
+ it,
15
+ vi,
16
+ } from "vitest";
17
+
18
+ // ---------------------------------------------------------------------------
19
+ // Module-level mocks — must be declared before any imports that pull in
20
+ // the module under test.
21
+ // ---------------------------------------------------------------------------
22
+
23
+ // Mock the cloud auth module
24
+ const mockCloudLogin = vi.fn();
25
+ vi.mock("../cloud/auth", () => ({
26
+ cloudLogin: (...args: unknown[]) => mockCloudLogin(...args),
27
+ }));
28
+
29
+ // Mock the cloud bridge client
30
+ const mockCreateAgent = vi.fn();
31
+ const mockGetAgent = vi.fn();
32
+ vi.mock("../cloud/bridge-client", () => ({
33
+ ElizaCloudClient: class {
34
+ createAgent = mockCreateAgent;
35
+ getAgent = mockGetAgent;
36
+ },
37
+ }));
38
+
39
+ // ---------------------------------------------------------------------------
40
+ // Import after mocks are set up
41
+ // ---------------------------------------------------------------------------
42
+
43
+ import {
44
+ type CloudOnboardingResult,
45
+ checkCloudAvailability,
46
+ runCloudOnboarding,
47
+ } from "./cloud-onboarding";
48
+
49
+ // ---------------------------------------------------------------------------
50
+ // Helpers — fake @clack/prompts module
51
+ // ---------------------------------------------------------------------------
52
+
53
+ function makeClack(
54
+ overrides: { selectReturn?: string; confirmReturns?: boolean[] } = {},
55
+ ) {
56
+ const { selectReturn = "cloud", confirmReturns = [] } = overrides;
57
+ let confirmIdx = 0;
58
+
59
+ return {
60
+ log: {
61
+ info: vi.fn(),
62
+ warn: vi.fn(),
63
+ success: vi.fn(),
64
+ error: vi.fn(),
65
+ message: vi.fn(),
66
+ },
67
+ spinner: () => ({
68
+ start: vi.fn(),
69
+ stop: vi.fn(),
70
+ message: vi.fn(),
71
+ }),
72
+ select: vi.fn().mockResolvedValue(selectReturn),
73
+ confirm: vi.fn().mockImplementation(() => {
74
+ const val = confirmReturns[confirmIdx] ?? true;
75
+ confirmIdx++;
76
+ return Promise.resolve(val);
77
+ }),
78
+ isCancel: vi.fn().mockReturnValue(false),
79
+ } as unknown as typeof import("@clack/prompts");
80
+ }
81
+
82
+ // ---------------------------------------------------------------------------
83
+ // checkCloudAvailability
84
+ // ---------------------------------------------------------------------------
85
+
86
+ describe("checkCloudAvailability", () => {
87
+ const originalFetch = globalThis.fetch;
88
+
89
+ afterEach(() => {
90
+ globalThis.fetch = originalFetch;
91
+ });
92
+
93
+ it("returns null when cloud is accepting new agents", async () => {
94
+ globalThis.fetch = vi.fn().mockResolvedValue({
95
+ ok: true,
96
+ json: async () => ({
97
+ success: true,
98
+ data: { acceptingNewAgents: true, availableSlots: 5 },
99
+ }),
100
+ }) as unknown as typeof fetch;
101
+
102
+ const result = await checkCloudAvailability("https://www.elizacloud.ai");
103
+ expect(result).toBeNull();
104
+ });
105
+
106
+ it("returns error message when cloud is at capacity", async () => {
107
+ globalThis.fetch = vi.fn().mockResolvedValue({
108
+ ok: true,
109
+ json: async () => ({
110
+ success: true,
111
+ data: { acceptingNewAgents: false, availableSlots: 0 },
112
+ }),
113
+ }) as unknown as typeof fetch;
114
+
115
+ const result = await checkCloudAvailability("https://www.elizacloud.ai");
116
+ expect(result).toContain("at capacity");
117
+ });
118
+
119
+ it("returns error message when cloud returns HTTP error", async () => {
120
+ globalThis.fetch = vi.fn().mockResolvedValue({
121
+ ok: false,
122
+ status: 503,
123
+ }) as unknown as typeof fetch;
124
+
125
+ const result = await checkCloudAvailability("https://www.elizacloud.ai");
126
+ expect(result).toContain("503");
127
+ });
128
+
129
+ it("returns error message when fetch throws (network error)", async () => {
130
+ globalThis.fetch = vi
131
+ .fn()
132
+ .mockRejectedValue(new Error("ECONNREFUSED")) as unknown as typeof fetch;
133
+
134
+ const result = await checkCloudAvailability("https://www.elizacloud.ai");
135
+ expect(result).toContain("ECONNREFUSED");
136
+ });
137
+
138
+ it("returns timeout message on timeout", async () => {
139
+ const err = new Error("timed out");
140
+ err.name = "TimeoutError";
141
+ globalThis.fetch = vi
142
+ .fn()
143
+ .mockRejectedValue(err) as unknown as typeof fetch;
144
+
145
+ const result = await checkCloudAvailability("https://www.elizacloud.ai");
146
+ expect(result).toContain("timed out");
147
+ });
148
+
149
+ it("normalises the base URL before fetching", async () => {
150
+ const mockFetch = vi.fn().mockResolvedValue({
151
+ ok: true,
152
+ json: async () => ({
153
+ success: true,
154
+ data: { acceptingNewAgents: true, availableSlots: 1 },
155
+ }),
156
+ }) as unknown as typeof fetch;
157
+ globalThis.fetch = mockFetch;
158
+
159
+ await checkCloudAvailability("https://elizacloud.ai/api/v1/");
160
+
161
+ // normalizeCloudSiteUrl should strip the /api/v1 and add www
162
+ const calledUrl = (mockFetch as unknown as ReturnType<typeof vi.fn>).mock
163
+ .calls[0][0];
164
+ expect(calledUrl).toContain("www.elizacloud.ai");
165
+ expect(calledUrl).toContain("/api/compat/availability");
166
+ expect(calledUrl).not.toContain("/api/v1/api/compat");
167
+ });
168
+ });
169
+
170
+ // ---------------------------------------------------------------------------
171
+ // runCloudOnboarding
172
+ // ---------------------------------------------------------------------------
173
+
174
+ describe("runCloudOnboarding", () => {
175
+ const originalFetch = globalThis.fetch;
176
+
177
+ beforeEach(() => {
178
+ mockCloudLogin.mockReset();
179
+ mockCreateAgent.mockReset();
180
+ mockGetAgent.mockReset();
181
+
182
+ // Default: cloud is available
183
+ globalThis.fetch = vi.fn().mockResolvedValue({
184
+ ok: true,
185
+ json: async () => ({
186
+ success: true,
187
+ data: { acceptingNewAgents: true, availableSlots: 5 },
188
+ }),
189
+ }) as unknown as typeof fetch;
190
+ });
191
+
192
+ afterEach(() => {
193
+ globalThis.fetch = originalFetch;
194
+ });
195
+
196
+ it("returns full result when auth + provisioning succeed", async () => {
197
+ const clack = makeClack();
198
+
199
+ mockCloudLogin.mockResolvedValue({
200
+ apiKey: "test-key-123",
201
+ keyPrefix: "test",
202
+ expiresAt: null,
203
+ });
204
+
205
+ mockCreateAgent.mockResolvedValue({
206
+ id: "agent-abc",
207
+ status: "running",
208
+ });
209
+
210
+ mockGetAgent.mockResolvedValue({
211
+ status: "running",
212
+ bridgeUrl: "https://bridge.example.com",
213
+ });
214
+
215
+ const result = await runCloudOnboarding(
216
+ clack,
217
+ "TestAgent",
218
+ undefined,
219
+ "https://www.elizacloud.ai",
220
+ );
221
+
222
+ assert(result != null, "expected a non-null result");
223
+ expect(result.apiKey).toBe("test-key-123");
224
+ expect(result.agentId).toBe("agent-abc");
225
+ expect(result.baseUrl).toContain("elizacloud.ai");
226
+ });
227
+
228
+ it("returns null when cloud is unavailable and user falls back to local", async () => {
229
+ const clack = makeClack({ confirmReturns: [true] }); // "run locally?"
230
+
231
+ globalThis.fetch = vi.fn().mockResolvedValue({
232
+ ok: true,
233
+ json: async () => ({
234
+ success: true,
235
+ data: { acceptingNewAgents: false, availableSlots: 0 },
236
+ }),
237
+ }) as unknown as typeof fetch;
238
+
239
+ const result = await runCloudOnboarding(
240
+ clack,
241
+ "TestAgent",
242
+ undefined,
243
+ "https://www.elizacloud.ai",
244
+ );
245
+
246
+ expect(result).toBeNull();
247
+ expect(mockCloudLogin).not.toHaveBeenCalled();
248
+ });
249
+
250
+ it("returns null when auth fails and user declines retry", async () => {
251
+ const clack = makeClack({ confirmReturns: [false] }); // "run locally" (cancel)
252
+
253
+ mockCloudLogin.mockResolvedValue(null);
254
+
255
+ const result = await runCloudOnboarding(
256
+ clack,
257
+ "TestAgent",
258
+ undefined,
259
+ "https://www.elizacloud.ai",
260
+ );
261
+
262
+ expect(result).toBeNull();
263
+ expect(mockCloudLogin).toHaveBeenCalledTimes(1);
264
+ });
265
+
266
+ it("retries auth once when user requests it", async () => {
267
+ const clack = makeClack({ confirmReturns: [true] }); // "try again"
268
+
269
+ // First attempt fails, second succeeds
270
+ mockCloudLogin.mockResolvedValueOnce(null).mockResolvedValueOnce({
271
+ apiKey: "retry-key",
272
+ keyPrefix: "retry",
273
+ expiresAt: null,
274
+ });
275
+
276
+ mockCreateAgent.mockResolvedValue({
277
+ id: "agent-retry",
278
+ status: "running",
279
+ });
280
+
281
+ mockGetAgent.mockResolvedValue({
282
+ status: "running",
283
+ bridgeUrl: "https://bridge.example.com",
284
+ });
285
+
286
+ const result = await runCloudOnboarding(
287
+ clack,
288
+ "TestAgent",
289
+ undefined,
290
+ "https://www.elizacloud.ai",
291
+ );
292
+
293
+ expect(mockCloudLogin).toHaveBeenCalledTimes(2);
294
+ assert(result != null, "expected a non-null result after retry");
295
+ expect(result.apiKey).toBe("retry-key");
296
+ });
297
+
298
+ it("returns auth-only result (agentId undefined) when provisioning fails and user declines local", async () => {
299
+ // User declines "continue with local setup?" AND declines "run locally?"
300
+ const clack = makeClack({ confirmReturns: [false] });
301
+
302
+ mockCloudLogin.mockResolvedValue({
303
+ apiKey: "auth-only-key",
304
+ keyPrefix: "auth",
305
+ expiresAt: null,
306
+ });
307
+
308
+ // provisionCloudAgent fails
309
+ mockCreateAgent.mockRejectedValue(new Error("quota exceeded"));
310
+
311
+ const result = await runCloudOnboarding(
312
+ clack,
313
+ "TestAgent",
314
+ undefined,
315
+ "https://www.elizacloud.ai",
316
+ );
317
+
318
+ assert(result != null, "expected a non-null auth-only result");
319
+ expect(result.apiKey).toBe("auth-only-key");
320
+ expect(result.agentId).toBeUndefined();
321
+ });
322
+
323
+ it("returns null when provisioning fails and user wants local", async () => {
324
+ const clack = makeClack({ confirmReturns: [true] }); // "continue with local?"
325
+
326
+ mockCloudLogin.mockResolvedValue({
327
+ apiKey: "key-123",
328
+ keyPrefix: "k",
329
+ expiresAt: null,
330
+ });
331
+
332
+ mockCreateAgent.mockRejectedValue(new Error("server error"));
333
+
334
+ const result = await runCloudOnboarding(
335
+ clack,
336
+ "TestAgent",
337
+ undefined,
338
+ "https://www.elizacloud.ai",
339
+ );
340
+
341
+ expect(result).toBeNull();
342
+ });
343
+ });
344
+
345
+ // ---------------------------------------------------------------------------
346
+ // provisionCloudAgent — tested indirectly via runCloudOnboarding
347
+ // ---------------------------------------------------------------------------
348
+
349
+ describe("provisionCloudAgent (via runCloudOnboarding)", () => {
350
+ const originalFetch = globalThis.fetch;
351
+
352
+ beforeEach(() => {
353
+ mockCloudLogin.mockReset();
354
+ mockCreateAgent.mockReset();
355
+ mockGetAgent.mockReset();
356
+
357
+ // Cloud is available
358
+ globalThis.fetch = vi.fn().mockResolvedValue({
359
+ ok: true,
360
+ json: async () => ({
361
+ success: true,
362
+ data: { acceptingNewAgents: true, availableSlots: 5 },
363
+ }),
364
+ }) as unknown as typeof fetch;
365
+
366
+ // Auth always succeeds
367
+ mockCloudLogin.mockResolvedValue({
368
+ apiKey: "test-key",
369
+ keyPrefix: "test",
370
+ expiresAt: null,
371
+ });
372
+ });
373
+
374
+ afterEach(() => {
375
+ globalThis.fetch = originalFetch;
376
+ });
377
+
378
+ it("polls until agent reaches running status", async () => {
379
+ const clack = makeClack();
380
+
381
+ mockCreateAgent.mockResolvedValue({
382
+ id: "agent-poll",
383
+ status: "provisioning",
384
+ });
385
+
386
+ // First poll: still provisioning. Second poll: running.
387
+ mockGetAgent
388
+ .mockResolvedValueOnce({ status: "provisioning" })
389
+ .mockResolvedValueOnce({
390
+ status: "running",
391
+ bridgeUrl: "https://bridge.test",
392
+ });
393
+
394
+ const result = await runCloudOnboarding(
395
+ clack,
396
+ "PollAgent",
397
+ undefined,
398
+ "https://www.elizacloud.ai",
399
+ );
400
+
401
+ assert(result != null, "expected a non-null result after polling");
402
+ expect(result.agentId).toBe("agent-poll");
403
+ expect(result.bridgeUrl).toBe("https://bridge.test");
404
+ expect(mockGetAgent).toHaveBeenCalledTimes(2);
405
+ });
406
+
407
+ it("returns null when agent provisioning fails with error status", async () => {
408
+ const clack = makeClack({ confirmReturns: [true] }); // fall back to local
409
+
410
+ mockCreateAgent.mockResolvedValue({
411
+ id: "agent-fail",
412
+ status: "provisioning",
413
+ });
414
+
415
+ mockGetAgent.mockResolvedValue({
416
+ status: "failed",
417
+ errorMessage: "out of resources",
418
+ });
419
+
420
+ const result = await runCloudOnboarding(
421
+ clack,
422
+ "FailAgent",
423
+ undefined,
424
+ "https://www.elizacloud.ai",
425
+ );
426
+
427
+ // Falls back to null because user chose local
428
+ expect(result).toBeNull();
429
+ });
430
+
431
+ it("passes style preset through to createAgent", async () => {
432
+ const clack = makeClack();
433
+
434
+ mockCreateAgent.mockResolvedValue({
435
+ id: "agent-styled",
436
+ status: "running",
437
+ });
438
+
439
+ mockGetAgent.mockResolvedValue({
440
+ status: "running",
441
+ bridgeUrl: "https://bridge.test",
442
+ });
443
+
444
+ const preset = {
445
+ catchphrase: "test",
446
+ bio: ["A test agent"],
447
+ system: "You are a test agent.",
448
+ adjectives: ["testy"],
449
+ topics: ["testing"],
450
+ };
451
+
452
+ await runCloudOnboarding(
453
+ clack,
454
+ "StyledAgent",
455
+ preset as Parameters<typeof runCloudOnboarding>[2],
456
+ "https://www.elizacloud.ai",
457
+ );
458
+
459
+ expect(mockCreateAgent).toHaveBeenCalledTimes(1);
460
+ const params = mockCreateAgent.mock.calls[0][0];
461
+ expect(params.agentName).toBe("StyledAgent");
462
+ expect(params.agentConfig.bio).toEqual(["A test agent"]);
463
+ expect(params.agentConfig.system).toBe("You are a test agent.");
464
+ });
465
+ });
466
+
467
+ // ---------------------------------------------------------------------------
468
+ // CloudOnboardingResult interface
469
+ // ---------------------------------------------------------------------------
470
+
471
+ describe("CloudOnboardingResult", () => {
472
+ it("agentId accepts string value", () => {
473
+ const result: CloudOnboardingResult = {
474
+ apiKey: "key",
475
+ agentId: "agent-123",
476
+ baseUrl: "https://example.com",
477
+ };
478
+ expect(result.agentId).toBe("agent-123");
479
+ });
480
+
481
+ it("agentId accepts undefined", () => {
482
+ const result: CloudOnboardingResult = {
483
+ apiKey: "key",
484
+ agentId: undefined,
485
+ baseUrl: "https://example.com",
486
+ };
487
+ expect(result.agentId).toBeUndefined();
488
+ });
489
+ });