@@ -28,10 +28,14 @@ interface GeminiDebugResponseMeta {
2828 body ?: string ;
2929 note ?: string ;
3030 error ?: unknown ;
31+ headersOverride ?: HeadersInit ;
3132}
3233
3334let requestCounter = 0 ;
3435
36+ /**
37+ * Begins a debug trace for a Gemini request, logging request metadata when debugging is enabled.
38+ */
3539export function startGeminiDebugRequest ( meta : GeminiDebugRequestMeta ) : GeminiDebugContext | null {
3640 if ( ! debugEnabled ) {
3741 return null ;
@@ -56,6 +60,9 @@ export function startGeminiDebugRequest(meta: GeminiDebugRequestMeta): GeminiDeb
5660 return { id, streaming : meta . streaming , startedAt : Date . now ( ) } ;
5761}
5862
63+ /**
64+ * Logs response details for a previously started debug trace when debugging is enabled.
65+ */
5966export function logGeminiDebugResponse (
6067 context : GeminiDebugContext | null | undefined ,
6168 response : Response ,
@@ -70,7 +77,9 @@ export function logGeminiDebugResponse(
7077 `[Gemini Debug ${ context . id } ] Response ${ response . status } ${ response . statusText } (${ durationMs } ms)` ,
7178 ) ;
7279 logDebug (
73- `[Gemini Debug ${ context . id } ] Response Headers: ${ JSON . stringify ( maskHeaders ( response . headers ) ) } ` ,
80+ `[Gemini Debug ${ context . id } ] Response Headers: ${ JSON . stringify (
81+ maskHeaders ( meta . headersOverride ?? response . headers ) ,
82+ ) } `,
7483 ) ;
7584
7685 if ( meta . note ) {
@@ -88,6 +97,9 @@ export function logGeminiDebugResponse(
8897 }
8998}
9099
100+ /**
101+ * Obscures sensitive headers and returns a plain object for logging.
102+ */
91103function maskHeaders ( headers ?: HeadersInit | Headers ) : Record < string , string > {
92104 if ( ! headers ) {
93105 return { } ;
@@ -105,6 +117,9 @@ function maskHeaders(headers?: HeadersInit | Headers): Record<string, string> {
105117 return result ;
106118}
107119
120+ /**
121+ * Produces a short, type-aware preview of a request/response body for logs.
122+ */
108123function formatBodyPreview ( body ?: BodyInit | null ) : string | undefined {
109124 if ( body == null ) {
110125 return undefined ;
@@ -129,17 +144,26 @@ function formatBodyPreview(body?: BodyInit | null): string | undefined {
129144 return `[${ body . constructor ?. name ?? typeof body } payload omitted]` ;
130145}
131146
147+ /**
148+ * Truncates long strings to a fixed preview length for logging.
149+ */
132150function truncateForLog ( text : string ) : string {
133151 if ( text . length <= MAX_BODY_PREVIEW_CHARS ) {
134152 return text ;
135153 }
136154 return `${ text . slice ( 0 , MAX_BODY_PREVIEW_CHARS ) } ... (truncated ${ text . length - MAX_BODY_PREVIEW_CHARS } chars)` ;
137155}
138156
157+ /**
158+ * Writes a single debug line using the configured writer.
159+ */
139160function logDebug ( line : string ) : void {
140161 logWriter ( line ) ;
141162}
142163
164+ /**
165+ * Converts unknown error-like values into printable strings.
166+ */
143167function formatError ( error : unknown ) : string {
144168 if ( error instanceof Error ) {
145169 return error . stack ?? error . message ;
@@ -151,11 +175,17 @@ function formatError(error: unknown): string {
151175 }
152176}
153177
178+ /**
179+ * Builds a timestamped log file path in the current working directory.
180+ */
154181function defaultLogFilePath ( ) : string {
155182 const timestamp = new Date ( ) . toISOString ( ) . replace ( / [: .] / g, "-" ) ;
156183 return join ( cwd ( ) , `gemini-debug-${ timestamp } .log` ) ;
157184}
158185
186+ /**
187+ * Creates a line writer that appends to a file when provided.
188+ */
159189function createLogWriter ( filePath ?: string ) : ( line : string ) => void {
160190 if ( ! filePath ) {
161191 return ( ) => { } ;
0 commit comments