import * as Effect from "effect/Effect"; import { dependencies, version } from "../package.json"; import { DIAGNOSTIC_LIMITS, type DiagnosticExport, } from "../shared/diagnostics"; import { AgentFailure, agentValidation } from "./agent-io"; import { diagnosticId, type DiagnosticStore } from "./diagnostics"; import { validateConversationId } from "./personal-conversations"; export function diagnosticExport( runtime: DiagnosticStore, conversationId: unknown, readConversation: ( id: string, ) => Effect.Effect< NonNullable, AgentFailure >, mcpConnections: DiagnosticExport["mcpConnections"] = [], ) { return Effect.gen(function* () { let conversation: DiagnosticExport["conversation"] = null; if (conversationId !== null) { const id = yield* agentValidation(() => { validateConversationId(conversationId); return conversationId; }); conversation = yield* readConversation(id); } const result: DiagnosticExport = { schemaVersion: 1, applicationVersion: version, sdkVersions: { agents: dependencies.agents, think: dependencies["@cloudflare/think"], ai: dependencies.ai, }, exportedAt: new Date().toISOString(), scope: { runtime: true, conversationId: diagnosticId(conversationId) }, limits: DIAGNOSTIC_LIMITS, availability: { history: "best-effort", unfinishedStarts: "outcome-unknown", usage: "reported-fields-only-workers-ai-zero-unavailable", cost: "unavailable", taskDuration: "claim-includes-queue-use-turn-duration-for-execution", content: "excluded", }, mcpConnections, runtime: runtime.snapshot(diagnosticId(conversationId)), conversation, }; if ( new TextEncoder().encode(JSON.stringify(result)).length > DIAGNOSTIC_LIMITS.maxExportBytes ) return yield* Effect.fail( new AgentFailure({ message: "Diagnostic export exceeds size limit" }), ); return result; }); }