1import type { ProviderDriverKind, ThreadId } from "@t3tools/contracts";
2import { causeErrorTag } from "@t3tools/shared/observability";
3import * as Cause from "effect/Cause";
4import * as SecureRandom from "effect/crypto/SecureRandom";
5import * as DateTime from "effect/DateTime";
6import * as Effect from "effect/Effect";
7
8import type * as ProviderEventLoggers from "@t3tools/provider-core/server/ProviderEventLoggers";
9import {
10 structuralProtocolMethod,
11 summarizeNativeProtocolPayload,
12} from "@t3tools/provider-core/server/nativeProtocolLogging";
13import type * as AcpSessionRuntime from "./AcpSessionRuntime.ts";
14
15function formatRequestLogPayload(event: AcpSessionRuntime.AcpSessionRequestLogEvent) {
16 return {
17 method: structuralProtocolMethod(event.method),
18 status: event.status,
19 request: summarizeNativeProtocolPayload(event.payload),
20 ...(event.result !== undefined ? { result: summarizeNativeProtocolPayload(event.result) } : {}),
21 ...(event.cause !== undefined
22 ? {
23 errorTag: causeErrorTag(event.cause),
24 reasonCount: event.cause.reasons.length,
25 }
26 : {}),
27 };
28}
29
30export const makeAcpNativeLoggerFactory = Effect.fn("makeAcpNativeLoggerFactory")(function* () {
31 const random = yield* SecureRandom.SecureRandom;
32 return (input: {
33 readonly nativeEventLogger: ProviderEventLoggers.EventNdjsonLogger | undefined;
34 readonly provider: ProviderDriverKind;
35 readonly threadId: ThreadId;
36 }): Pick<AcpSessionRuntime.AcpSessionRuntimeOptions, "requestLogger" | "protocolLogging"> => {
37 const writeNativeAcpLog = Effect.fn("AcpNativeLogging.writeNativeAcpLog")(
38 function* (logInput: { readonly kind: "request"; readonly payload: unknown }) {
39 if (!input.nativeEventLogger) return;
40 const observedAt = DateTime.formatIso(yield* DateTime.now);
41 yield* input.nativeEventLogger.write(
42 {
43 observedAt,
44 event: {
45 id: yield* random.uuidV4(),
46 kind: logInput.kind,
47 provider: input.provider,
48 createdAt: observedAt,
49 threadId: input.threadId,
50 payload: logInput.payload,
51 },
52 },
53 input.threadId,
54 );
55 },
56 Effect.catchCause((cause) =>
57 Cause.hasInterrupts(cause)
58 ? Effect.interrupt
59 : Effect.logWarning("Failed to write native ACP event log.", {
60 errorTag: causeErrorTag(cause),
61 reasonCount: cause.reasons.length,
62 provider: input.provider,
63 threadId: input.threadId,
64 }),
65 ),
66 );
67
68 return {
69 requestLogger: (event: AcpSessionRuntime.AcpSessionRequestLogEvent) =>
70 writeNativeAcpLog({
71 kind: "request",
72 payload: formatRequestLogPayload(event),
73 }),
74 };
75 };
76});