@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,714 @@
1
+ /**
2
+ * Trajectory API routes for the Milady Control UI.
3
+ *
4
+ * Provides endpoints for:
5
+ * - Listing and searching trajectories
6
+ * - Viewing trajectory details with LLM calls and provider accesses
7
+ * - Exporting trajectories to JSON, CSV, or ZIP
8
+ * - Deleting trajectories
9
+ * - Getting trajectory statistics
10
+ * - Enabling/disabling trajectory logging
11
+ *
12
+ * Uses the @elizaos/plugin-trajectory-logger service for data access.
13
+ */
14
+
15
+ import type http from "node:http";
16
+ import type { AgentRuntime } from "@elizaos/core";
17
+ import {
18
+ readJsonBody as parseJsonBody,
19
+ sendJson,
20
+ sendJsonError,
21
+ } from "./http-helpers";
22
+ import { createZipArchive } from "./zip-utils";
23
+
24
+ // ============================================================================
25
+ // Types
26
+ // ============================================================================
27
+
28
+ type TrajectoryStatus = "active" | "completed" | "error" | "timeout";
29
+
30
+ interface TrajectoryListOptions {
31
+ limit?: number;
32
+ offset?: number;
33
+ source?: string;
34
+ status?: TrajectoryStatus;
35
+ startDate?: string;
36
+ endDate?: string;
37
+ search?: string;
38
+ scenarioId?: string;
39
+ batchId?: string;
40
+ isTrainingData?: boolean;
41
+ }
42
+
43
+ interface TrajectoryListItem {
44
+ id: string;
45
+ agentId: string;
46
+ source: string;
47
+ status: TrajectoryStatus;
48
+ startTime: number;
49
+ endTime: number | null;
50
+ durationMs: number | null;
51
+ llmCallCount: number;
52
+ totalPromptTokens: number;
53
+ totalCompletionTokens: number;
54
+ createdAt: string;
55
+ }
56
+
57
+ interface TrajectoryLlmCall {
58
+ callId?: string;
59
+ timestamp?: number;
60
+ model?: string;
61
+ systemPrompt?: string;
62
+ userPrompt?: string;
63
+ response?: string;
64
+ temperature?: number;
65
+ maxTokens?: number;
66
+ purpose?: string;
67
+ actionType?: string;
68
+ latencyMs?: number;
69
+ promptTokens?: number;
70
+ completionTokens?: number;
71
+ }
72
+
73
+ interface TrajectoryProviderAccess {
74
+ providerId?: string;
75
+ providerName?: string;
76
+ purpose?: string;
77
+ data?: Record<string, unknown>;
78
+ query?: Record<string, unknown>;
79
+ timestamp?: number;
80
+ }
81
+
82
+ interface TrajectoryStep {
83
+ stepId?: string;
84
+ timestamp: number;
85
+ llmCalls?: TrajectoryLlmCall[];
86
+ providerAccesses?: TrajectoryProviderAccess[];
87
+ }
88
+
89
+ interface Trajectory {
90
+ trajectoryId: string;
91
+ agentId: string;
92
+ startTime: number;
93
+ endTime?: number;
94
+ durationMs?: number;
95
+ steps?: TrajectoryStep[];
96
+ metrics?: { finalStatus?: string };
97
+ metadata?: Record<string, unknown>;
98
+ }
99
+
100
+ interface TrajectoryListResult {
101
+ trajectories: TrajectoryListItem[];
102
+ total: number;
103
+ offset: number;
104
+ limit: number;
105
+ }
106
+
107
+ type TrajectoryExportFormat = "json" | "csv" | "art";
108
+
109
+ interface TrajectoryExportOptions {
110
+ format: TrajectoryExportFormat;
111
+ includePrompts?: boolean;
112
+ trajectoryIds?: string[];
113
+ startDate?: string;
114
+ endDate?: string;
115
+ scenarioId?: string;
116
+ batchId?: string;
117
+ }
118
+
119
+ interface TrajectoryExportResult {
120
+ filename: string;
121
+ data: string | Uint8Array;
122
+ mimeType: string;
123
+ }
124
+
125
+ interface TrajectoryLoggerApi {
126
+ isEnabled(): boolean;
127
+ setEnabled(enabled: boolean): void;
128
+ listTrajectories(
129
+ options: TrajectoryListOptions,
130
+ ): Promise<TrajectoryListResult>;
131
+ getTrajectoryDetail(trajectoryId: string): Promise<Trajectory | null>;
132
+ getStats(): Promise<unknown>;
133
+ deleteTrajectories(trajectoryIds: string[]): Promise<number>;
134
+ clearAllTrajectories(): Promise<number>;
135
+ exportTrajectories(
136
+ options: TrajectoryExportOptions,
137
+ ): Promise<TrajectoryExportResult>;
138
+ exportTrajectoriesZip?: (
139
+ options: TrajectoryZipExportOptions,
140
+ ) => Promise<TrajectoryZipExportResult>;
141
+ }
142
+
143
+ type TrajectoryZipExportOptions = {
144
+ includePrompts?: boolean;
145
+ trajectoryIds?: string[];
146
+ startDate?: string;
147
+ endDate?: string;
148
+ scenarioId?: string;
149
+ batchId?: string;
150
+ };
151
+
152
+ type TrajectoryZipExportResult = {
153
+ filename: string;
154
+ entries: Array<{ name: string; data: string }>;
155
+ };
156
+
157
+ // UI Compatible Types
158
+
159
+ interface UITrajectoryRecord {
160
+ id: string;
161
+ agentId: string;
162
+ roomId: string | null;
163
+ entityId: string | null;
164
+ conversationId: string | null;
165
+ source: string;
166
+ status: "active" | "completed" | "error";
167
+ startTime: number;
168
+ endTime: number | null;
169
+ durationMs: number | null;
170
+ llmCallCount: number;
171
+ providerAccessCount: number;
172
+ totalPromptTokens: number;
173
+ totalCompletionTokens: number;
174
+ metadata: Record<string, unknown>;
175
+ createdAt: string;
176
+ updatedAt: string;
177
+ }
178
+
179
+ interface UILlmCall {
180
+ id: string;
181
+ trajectoryId: string;
182
+ stepId: string;
183
+ model: string;
184
+ systemPrompt: string;
185
+ userPrompt: string;
186
+ response: string;
187
+ temperature: number;
188
+ maxTokens: number;
189
+ purpose: string;
190
+ actionType: string;
191
+ latencyMs: number;
192
+ promptTokens?: number;
193
+ completionTokens?: number;
194
+ timestamp: number;
195
+ createdAt: string;
196
+ }
197
+
198
+ interface UIProviderAccess {
199
+ id: string;
200
+ trajectoryId: string;
201
+ stepId: string;
202
+ providerName: string;
203
+ purpose: string;
204
+ data: Record<string, unknown>;
205
+ query?: Record<string, unknown>;
206
+ timestamp: number;
207
+ createdAt: string;
208
+ }
209
+
210
+ interface UITrajectoryDetailResult {
211
+ trajectory: UITrajectoryRecord;
212
+ llmCalls: UILlmCall[];
213
+ providerAccesses: UIProviderAccess[];
214
+ }
215
+
216
+ // ============================================================================
217
+ // Helpers
218
+ // ============================================================================
219
+
220
+ function isRouteCompatibleTrajectoryLogger(
221
+ candidate: unknown,
222
+ ): candidate is TrajectoryLoggerApi {
223
+ if (!candidate || typeof candidate !== "object") return false;
224
+ const logger = candidate as Partial<TrajectoryLoggerApi>;
225
+
226
+ return (
227
+ typeof logger.isEnabled === "function" &&
228
+ typeof logger.setEnabled === "function" &&
229
+ typeof logger.listTrajectories === "function" &&
230
+ typeof logger.getTrajectoryDetail === "function" &&
231
+ typeof logger.getStats === "function" &&
232
+ typeof logger.deleteTrajectories === "function" &&
233
+ typeof logger.clearAllTrajectories === "function" &&
234
+ typeof logger.exportTrajectories === "function"
235
+ );
236
+ }
237
+
238
+ function getTrajectoryLogger(
239
+ runtime: AgentRuntime,
240
+ ): TrajectoryLoggerApi | null {
241
+ const runtimeLike = runtime as AgentRuntime & {
242
+ getServicesByType?: (serviceType: string) => unknown;
243
+ getService?: (serviceType: string) => unknown;
244
+ };
245
+
246
+ const seen = new Set<unknown>();
247
+ const candidates: unknown[] = [];
248
+ const addCandidate = (candidate: unknown): void => {
249
+ if (!candidate || seen.has(candidate)) return;
250
+ seen.add(candidate);
251
+ candidates.push(candidate);
252
+ };
253
+
254
+ if (typeof runtimeLike.getServicesByType === "function") {
255
+ const byType = runtimeLike.getServicesByType("trajectory_logger");
256
+ if (Array.isArray(byType)) {
257
+ for (const candidate of byType) {
258
+ addCandidate(candidate);
259
+ }
260
+ } else {
261
+ addCandidate(byType);
262
+ }
263
+ }
264
+
265
+ if (typeof runtimeLike.getService === "function") {
266
+ addCandidate(runtimeLike.getService("trajectory_logger"));
267
+ }
268
+
269
+ for (const candidate of candidates) {
270
+ if (isRouteCompatibleTrajectoryLogger(candidate)) {
271
+ return candidate;
272
+ }
273
+ }
274
+
275
+ return null;
276
+ }
277
+
278
+ function toNullableString(value: unknown): string | null {
279
+ return typeof value === "string" ? value : null;
280
+ }
281
+
282
+ function listItemToUIRecord(item: TrajectoryListItem): UITrajectoryRecord {
283
+ const status =
284
+ item.status === "timeout" || item.status === "error"
285
+ ? "error"
286
+ : item.status;
287
+ return {
288
+ id: item.id,
289
+ agentId: item.agentId,
290
+ roomId: null,
291
+ entityId: null,
292
+ conversationId: null,
293
+ source: item.source,
294
+ status: status as "active" | "completed" | "error",
295
+ startTime: item.startTime,
296
+ endTime: item.endTime,
297
+ durationMs: item.durationMs,
298
+ llmCallCount: item.llmCallCount,
299
+ providerAccessCount: 0,
300
+ totalPromptTokens: item.totalPromptTokens,
301
+ totalCompletionTokens: item.totalCompletionTokens,
302
+ metadata: {},
303
+ createdAt: item.createdAt,
304
+ updatedAt: item.createdAt,
305
+ };
306
+ }
307
+
308
+ function trajectoryToUIDetail(traj: Trajectory): UITrajectoryDetailResult {
309
+ const finalStatus = (traj.metrics?.finalStatus as string) ?? "completed";
310
+ const normalizedEndTime =
311
+ typeof traj.endTime === "number" && traj.endTime > 0 ? traj.endTime : null;
312
+ const status: "active" | "completed" | "error" =
313
+ finalStatus === "timeout" ||
314
+ finalStatus === "terminated" ||
315
+ finalStatus === "error"
316
+ ? "error"
317
+ : finalStatus === "completed"
318
+ ? "completed"
319
+ : normalizedEndTime
320
+ ? "completed"
321
+ : "active";
322
+
323
+ const llmCalls: UILlmCall[] = [];
324
+ const providerAccesses: UIProviderAccess[] = [];
325
+
326
+ let totalPromptTokens = 0;
327
+ let totalCompletionTokens = 0;
328
+
329
+ const steps = traj.steps || [];
330
+ const trajectoryId = String(traj.trajectoryId);
331
+
332
+ for (let i = 0; i < steps.length; i++) {
333
+ const step = steps[i];
334
+ const stepId = typeof step.stepId === "string" ? step.stepId : `step-${i}`;
335
+
336
+ // Process LLM Calls
337
+ const calls = step.llmCalls || [];
338
+ for (let j = 0; j < calls.length; j++) {
339
+ const call = calls[j];
340
+ llmCalls.push({
341
+ id: call.callId || `${stepId}-call-${j}`,
342
+ trajectoryId,
343
+ stepId,
344
+ model: call.model || "unknown",
345
+ systemPrompt: call.systemPrompt || "",
346
+ userPrompt: call.userPrompt || "",
347
+ response: call.response || "",
348
+ temperature:
349
+ typeof call.temperature === "number" ? call.temperature : 0,
350
+ maxTokens: typeof call.maxTokens === "number" ? call.maxTokens : 0,
351
+ purpose: call.purpose || "",
352
+ actionType: call.actionType || "",
353
+ latencyMs: call.latencyMs || 0,
354
+ promptTokens: call.promptTokens,
355
+ completionTokens: call.completionTokens,
356
+ timestamp: call.timestamp || step.timestamp,
357
+ createdAt: new Date(call.timestamp || step.timestamp).toISOString(),
358
+ });
359
+ totalPromptTokens += call.promptTokens || 0;
360
+ totalCompletionTokens += call.completionTokens || 0;
361
+ }
362
+
363
+ // Process Provider Accesses
364
+ const accesses = step.providerAccesses || [];
365
+ for (let k = 0; k < accesses.length; k++) {
366
+ const access = accesses[k];
367
+ providerAccesses.push({
368
+ id: access.providerId || `${stepId}-provider-${k}`,
369
+ trajectoryId,
370
+ stepId,
371
+ providerName: access.providerName || "unknown",
372
+ purpose: access.purpose || "",
373
+ data: access.data || {},
374
+ query: access.query,
375
+ timestamp: access.timestamp || step.timestamp,
376
+ createdAt: new Date(access.timestamp || step.timestamp).toISOString(),
377
+ });
378
+ }
379
+ }
380
+
381
+ const metadata = (traj.metadata ?? {}) as Record<string, unknown>;
382
+ const normalizedDurationMs =
383
+ status === "active"
384
+ ? null
385
+ : typeof traj.durationMs === "number"
386
+ ? traj.durationMs
387
+ : null;
388
+ const updatedAtMs = normalizedEndTime ?? (traj.startTime || Date.now());
389
+
390
+ const trajectory: UITrajectoryRecord = {
391
+ id: trajectoryId,
392
+ agentId: String(traj.agentId),
393
+ roomId: toNullableString(metadata.roomId),
394
+ entityId: toNullableString(metadata.entityId),
395
+ conversationId: toNullableString(metadata.conversationId),
396
+ source: toNullableString(metadata.source) ?? "chat",
397
+ status,
398
+ startTime: traj.startTime,
399
+ endTime: normalizedEndTime,
400
+ durationMs: normalizedDurationMs,
401
+ llmCallCount: llmCalls.length,
402
+ providerAccessCount: providerAccesses.length,
403
+ totalPromptTokens,
404
+ totalCompletionTokens,
405
+ metadata,
406
+ createdAt: new Date(traj.startTime).toISOString(),
407
+ updatedAt: new Date(updatedAtMs).toISOString(),
408
+ };
409
+
410
+ return { trajectory, llmCalls, providerAccesses };
411
+ }
412
+
413
+ // ============================================================================
414
+ // Handlers
415
+ // ============================================================================
416
+
417
+ async function handleGetTrajectories(
418
+ req: http.IncomingMessage,
419
+ res: http.ServerResponse,
420
+ runtime: AgentRuntime,
421
+ ): Promise<void> {
422
+ const logger = getTrajectoryLogger(runtime);
423
+ if (!logger) {
424
+ sendJsonError(res, "Trajectory logger service not available", 503);
425
+ return;
426
+ }
427
+
428
+ const url = new URL(
429
+ req.url ?? "/",
430
+ `http://${req.headers.host ?? "localhost"}`,
431
+ );
432
+
433
+ const options: TrajectoryListOptions = {
434
+ limit: Math.min(
435
+ 500,
436
+ Math.max(1, Number(url.searchParams.get("limit")) || 50),
437
+ ),
438
+ offset: Math.max(0, Number(url.searchParams.get("offset")) || 0),
439
+ source: url.searchParams.get("source") || undefined,
440
+ status:
441
+ (url.searchParams.get("status") as
442
+ | "active"
443
+ | "completed"
444
+ | "error"
445
+ | "timeout") || undefined,
446
+ startDate: url.searchParams.get("startDate") || undefined,
447
+ endDate: url.searchParams.get("endDate") || undefined,
448
+ search: url.searchParams.get("search") || undefined,
449
+ scenarioId: url.searchParams.get("scenarioId") || undefined,
450
+ batchId: url.searchParams.get("batchId") || undefined,
451
+ isTrainingData: url.searchParams.has("isTrainingData")
452
+ ? url.searchParams.get("isTrainingData") === "true"
453
+ : undefined,
454
+ };
455
+
456
+ const result = await logger.listTrajectories(options);
457
+
458
+ const uiResult = {
459
+ trajectories: result.trajectories.map(listItemToUIRecord),
460
+ total: result.total,
461
+ offset: result.offset,
462
+ limit: result.limit,
463
+ };
464
+
465
+ sendJson(res, uiResult);
466
+ }
467
+
468
+ async function handleGetTrajectoryDetail(
469
+ _req: http.IncomingMessage,
470
+ res: http.ServerResponse,
471
+ runtime: AgentRuntime,
472
+ trajectoryId: string,
473
+ ): Promise<void> {
474
+ const logger = getTrajectoryLogger(runtime);
475
+ if (!logger) {
476
+ sendJsonError(res, "Trajectory logger service not available", 503);
477
+ return;
478
+ }
479
+
480
+ const trajectory = await logger.getTrajectoryDetail(trajectoryId);
481
+ if (!trajectory) {
482
+ sendJsonError(res, `Trajectory "${trajectoryId}" not found`, 404);
483
+ return;
484
+ }
485
+
486
+ const uiDetail = trajectoryToUIDetail(trajectory);
487
+ sendJson(res, uiDetail);
488
+ }
489
+
490
+ async function handleGetStats(
491
+ _req: http.IncomingMessage,
492
+ res: http.ServerResponse,
493
+ runtime: AgentRuntime,
494
+ ): Promise<void> {
495
+ const logger = getTrajectoryLogger(runtime);
496
+ if (!logger) {
497
+ sendJsonError(res, "Trajectory logger service not available", 503);
498
+ return;
499
+ }
500
+
501
+ const stats = await logger.getStats();
502
+ sendJson(res, stats);
503
+ }
504
+
505
+ async function handleGetConfig(
506
+ _req: http.IncomingMessage,
507
+ res: http.ServerResponse,
508
+ runtime: AgentRuntime,
509
+ ): Promise<void> {
510
+ const logger = getTrajectoryLogger(runtime);
511
+ if (!logger) {
512
+ sendJsonError(res, "Trajectory logger service not available", 503);
513
+ return;
514
+ }
515
+
516
+ sendJson(res, {
517
+ enabled: logger.isEnabled(),
518
+ });
519
+ }
520
+
521
+ async function handlePutConfig(
522
+ req: http.IncomingMessage,
523
+ res: http.ServerResponse,
524
+ runtime: AgentRuntime,
525
+ ): Promise<void> {
526
+ const logger = getTrajectoryLogger(runtime);
527
+ if (!logger) {
528
+ sendJsonError(res, "Trajectory logger service not available", 503);
529
+ return;
530
+ }
531
+
532
+ const body = await parseJsonBody<{ enabled?: boolean }>(req, res);
533
+ if (!body) return;
534
+
535
+ if (typeof body.enabled === "boolean") {
536
+ logger.setEnabled(body.enabled);
537
+ }
538
+
539
+ sendJson(res, {
540
+ enabled: logger.isEnabled(),
541
+ });
542
+ }
543
+
544
+ async function handleExportTrajectories(
545
+ req: http.IncomingMessage,
546
+ res: http.ServerResponse,
547
+ runtime: AgentRuntime,
548
+ ): Promise<void> {
549
+ const logger = getTrajectoryLogger(runtime);
550
+ if (!logger) {
551
+ sendJsonError(res, "Trajectory logger service not available", 503);
552
+ return;
553
+ }
554
+
555
+ const body = await parseJsonBody<{
556
+ format?: string;
557
+ includePrompts?: boolean;
558
+ trajectoryIds?: string[];
559
+ startDate?: string;
560
+ endDate?: string;
561
+ scenarioId?: string;
562
+ batchId?: string;
563
+ }>(req, res);
564
+ if (!body) return;
565
+
566
+ if (body.format === "zip") {
567
+ if (typeof logger.exportTrajectoriesZip !== "function") {
568
+ sendJsonError(
569
+ res,
570
+ "Trajectory ZIP export is unavailable in the active logger",
571
+ 503,
572
+ );
573
+ return;
574
+ }
575
+
576
+ const zipOptions: TrajectoryZipExportOptions = {
577
+ includePrompts: body.includePrompts,
578
+ trajectoryIds: body.trajectoryIds,
579
+ startDate: body.startDate,
580
+ endDate: body.endDate,
581
+ scenarioId: body.scenarioId,
582
+ batchId: body.batchId,
583
+ };
584
+ const zipResult = await logger.exportTrajectoriesZip(zipOptions);
585
+ const archive = createZipArchive(zipResult.entries);
586
+
587
+ res.statusCode = 200;
588
+ res.setHeader("Content-Type", "application/zip");
589
+ res.setHeader(
590
+ "Content-Disposition",
591
+ `attachment; filename="${zipResult.filename}"`,
592
+ );
593
+ res.end(archive);
594
+ return;
595
+ }
596
+
597
+ if (
598
+ body.format !== "json" &&
599
+ body.format !== "csv" &&
600
+ body.format !== "art"
601
+ ) {
602
+ sendJsonError(res, "Format must be 'json', 'csv', 'art', or 'zip'", 400);
603
+ return;
604
+ }
605
+
606
+ const result = await logger.exportTrajectories({
607
+ format: body.format,
608
+ includePrompts: body.includePrompts,
609
+ trajectoryIds: body.trajectoryIds,
610
+ startDate: body.startDate,
611
+ endDate: body.endDate,
612
+ scenarioId: body.scenarioId,
613
+ batchId: body.batchId,
614
+ });
615
+
616
+ res.statusCode = 200;
617
+ res.setHeader("Content-Type", result.mimeType);
618
+ res.setHeader(
619
+ "Content-Disposition",
620
+ `attachment; filename="${result.filename}"`,
621
+ );
622
+ res.end(result.data);
623
+ }
624
+
625
+ async function handleDeleteTrajectories(
626
+ req: http.IncomingMessage,
627
+ res: http.ServerResponse,
628
+ runtime: AgentRuntime,
629
+ ): Promise<void> {
630
+ const logger = getTrajectoryLogger(runtime);
631
+ if (!logger) {
632
+ sendJsonError(res, "Trajectory logger service not available", 503);
633
+ return;
634
+ }
635
+
636
+ const body = await parseJsonBody<{
637
+ trajectoryIds?: string[];
638
+ all?: boolean;
639
+ }>(req, res);
640
+ if (!body) return;
641
+
642
+ if (body.all) {
643
+ const deletedCount = await logger.clearAllTrajectories();
644
+ sendJson(res, { deleted: deletedCount });
645
+ return;
646
+ }
647
+
648
+ if (Array.isArray(body.trajectoryIds) && body.trajectoryIds.length > 0) {
649
+ const deletedCount = await logger.deleteTrajectories(body.trajectoryIds);
650
+ sendJson(res, { deleted: deletedCount });
651
+ return;
652
+ }
653
+
654
+ sendJson(res, { deleted: 0 });
655
+ }
656
+
657
+ // ============================================================================
658
+ // Main Router
659
+ // ============================================================================
660
+
661
+ export async function handleTrajectoryRoute(
662
+ req: http.IncomingMessage,
663
+ res: http.ServerResponse,
664
+ runtime: AgentRuntime,
665
+ pathname: string,
666
+ method: string,
667
+ ): Promise<boolean> {
668
+ if (!pathname.startsWith("/api/trajectories")) return false;
669
+
670
+ // GET /api/trajectories/config
671
+ if (pathname === "/api/trajectories/config" && method === "GET") {
672
+ await handleGetConfig(req, res, runtime);
673
+ return true;
674
+ }
675
+
676
+ // PUT /api/trajectories/config
677
+ if (pathname === "/api/trajectories/config" && method === "PUT") {
678
+ await handlePutConfig(req, res, runtime);
679
+ return true;
680
+ }
681
+
682
+ // POST /api/trajectories/export
683
+ if (pathname === "/api/trajectories/export" && method === "POST") {
684
+ await handleExportTrajectories(req, res, runtime);
685
+ return true;
686
+ }
687
+
688
+ // DELETE /api/trajectories
689
+ if (pathname === "/api/trajectories" && method === "DELETE") {
690
+ await handleDeleteTrajectories(req, res, runtime);
691
+ return true;
692
+ }
693
+
694
+ // GET /api/trajectories/stats
695
+ if (pathname === "/api/trajectories/stats" && method === "GET") {
696
+ await handleGetStats(req, res, runtime);
697
+ return true;
698
+ }
699
+
700
+ // GET /api/trajectories/:id
701
+ const detailMatch = pathname.match(/^\/api\/trajectories\/([^/]+)$/);
702
+ if (detailMatch && method === "GET") {
703
+ await handleGetTrajectoryDetail(req, res, runtime, detailMatch[1]);
704
+ return true;
705
+ }
706
+
707
+ // GET /api/trajectories
708
+ if (pathname === "/api/trajectories" && method === "GET") {
709
+ await handleGetTrajectories(req, res, runtime);
710
+ return true;
711
+ }
712
+
713
+ return false;
714
+ }