@tanstack/ai 0.12.0 → 0.13.0

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 (58) hide show
  1. package/dist/esm/activities/chat/adapter.d.ts +6 -1
  2. package/dist/esm/activities/chat/adapter.js.map +1 -1
  3. package/dist/esm/activities/chat/index.d.ts +8 -0
  4. package/dist/esm/activities/chat/index.js +78 -17
  5. package/dist/esm/activities/chat/index.js.map +1 -1
  6. package/dist/esm/activities/chat/middleware/compose.d.ts +3 -1
  7. package/dist/esm/activities/chat/middleware/compose.js +79 -1
  8. package/dist/esm/activities/chat/middleware/compose.js.map +1 -1
  9. package/dist/esm/activities/generateImage/index.d.ts +7 -0
  10. package/dist/esm/activities/generateImage/index.js +19 -3
  11. package/dist/esm/activities/generateImage/index.js.map +1 -1
  12. package/dist/esm/activities/generateSpeech/index.d.ts +7 -0
  13. package/dist/esm/activities/generateSpeech/index.js +21 -3
  14. package/dist/esm/activities/generateSpeech/index.js.map +1 -1
  15. package/dist/esm/activities/generateTranscription/index.d.ts +7 -0
  16. package/dist/esm/activities/generateTranscription/index.js +32 -13
  17. package/dist/esm/activities/generateTranscription/index.js.map +1 -1
  18. package/dist/esm/activities/generateVideo/index.d.ts +7 -0
  19. package/dist/esm/activities/generateVideo/index.js +49 -7
  20. package/dist/esm/activities/generateVideo/index.js.map +1 -1
  21. package/dist/esm/activities/summarize/index.d.ts +7 -0
  22. package/dist/esm/activities/summarize/index.js +54 -19
  23. package/dist/esm/activities/summarize/index.js.map +1 -1
  24. package/dist/esm/adapter-internals.d.ts +3 -0
  25. package/dist/esm/adapter-internals.js +7 -0
  26. package/dist/esm/adapter-internals.js.map +1 -0
  27. package/dist/esm/index.d.ts +2 -0
  28. package/dist/esm/index.js +2 -0
  29. package/dist/esm/index.js.map +1 -1
  30. package/dist/esm/logger/console-logger.d.ts +11 -0
  31. package/dist/esm/logger/console-logger.js +27 -0
  32. package/dist/esm/logger/console-logger.js.map +1 -0
  33. package/dist/esm/logger/internal-logger.d.ts +33 -0
  34. package/dist/esm/logger/internal-logger.js +69 -0
  35. package/dist/esm/logger/internal-logger.js.map +1 -0
  36. package/dist/esm/logger/resolve.d.ts +14 -0
  37. package/dist/esm/logger/resolve.js +54 -0
  38. package/dist/esm/logger/resolve.js.map +1 -0
  39. package/dist/esm/logger/types.d.ts +75 -0
  40. package/dist/esm/types.d.ts +34 -0
  41. package/package.json +6 -2
  42. package/skills/ai-core/SKILL.md +5 -3
  43. package/skills/ai-core/debug-logging/SKILL.md +263 -0
  44. package/src/activities/chat/adapter.ts +6 -1
  45. package/src/activities/chat/index.ts +104 -22
  46. package/src/activities/chat/middleware/compose.ts +84 -1
  47. package/src/activities/generateImage/index.ts +29 -3
  48. package/src/activities/generateSpeech/index.ts +35 -3
  49. package/src/activities/generateTranscription/index.ts +45 -13
  50. package/src/activities/generateVideo/index.ts +65 -6
  51. package/src/activities/summarize/index.ts +66 -20
  52. package/src/adapter-internals.ts +7 -0
  53. package/src/index.ts +9 -0
  54. package/src/logger/console-logger.ts +49 -0
  55. package/src/logger/internal-logger.ts +107 -0
  56. package/src/logger/resolve.ts +72 -0
  57. package/src/logger/types.ts +78 -0
  58. package/src/types.ts +36 -0
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Pluggable logger interface consumed by every `@tanstack/ai` activity when `debug` is enabled. Supply a custom implementation via `debug: { logger }` on `chat()`, `summarize()`, `generateImage()`, etc. The four methods correspond to log levels: use `debug` for chunk-level diagnostic output, `info`/`warn` for notable events, `error` for caught exceptions.
3
+ */
4
+ export interface Logger {
5
+ /**
6
+ * Called for chunk-level diagnostic output (raw provider chunks, per-chunk output, agent-loop iteration markers).
7
+ * @param meta Structured data forwarded to the underlying logger. Loggers like pino will preserve this as a structured record; console-based loggers pass it as the second argument to `console.<level>`.
8
+ */
9
+ debug: (message: string, meta?: Record<string, unknown>) => void;
10
+ /**
11
+ * Called for notable informational events (outgoing requests, tool invocations, middleware transitions).
12
+ * @param meta Structured data forwarded to the underlying logger. Loggers like pino will preserve this as a structured record; console-based loggers pass it as the second argument to `console.<level>`.
13
+ */
14
+ info: (message: string, meta?: Record<string, unknown>) => void;
15
+ /**
16
+ * Called for notable warnings that don't halt execution (deprecations, recoverable anomalies).
17
+ * @param meta Structured data forwarded to the underlying logger. Loggers like pino will preserve this as a structured record; console-based loggers pass it as the second argument to `console.<level>`.
18
+ */
19
+ warn: (message: string, meta?: Record<string, unknown>) => void;
20
+ /**
21
+ * Called for caught exceptions throughout the pipeline.
22
+ * @param meta Structured data forwarded to the underlying logger. Loggers like pino will preserve this as a structured record; console-based loggers pass it as the second argument to `console.<level>`.
23
+ */
24
+ error: (message: string, meta?: Record<string, unknown>) => void;
25
+ }
26
+ /**
27
+ * Per-category toggles for debug logging. Each flag enables or disables one class of log message. Unspecified flags default to `true` when `DebugConfig` is partially specified; `undefined` on the `debug` option defaults all flags to `false` except `errors`.
28
+ */
29
+ export interface DebugCategories {
30
+ /**
31
+ * Raw chunks/frames received from a provider SDK (OpenAI, Anthropic, Gemini, Ollama, Grok, Groq, OpenRouter, fal, ElevenLabs). Emitted inside every streaming adapter's chunk loop.
32
+ */
33
+ provider?: boolean;
34
+ /**
35
+ * Chunks/results yielded to the consumer after all middleware. For streaming activities this fires per chunk; for non-streaming activities it fires once per result.
36
+ */
37
+ output?: boolean;
38
+ /**
39
+ * Inputs and outputs around each middleware hook invocation. Chat-only.
40
+ */
41
+ middleware?: boolean;
42
+ /**
43
+ * Before/after tool-call execution in the chat agent loop. Chat-only.
44
+ */
45
+ tools?: boolean;
46
+ /**
47
+ * Iteration markers and phase transitions in the chat agent loop. Chat-only.
48
+ */
49
+ agentLoop?: boolean;
50
+ /**
51
+ * Config transforms returned by middleware `onConfig` hooks. Chat-only.
52
+ */
53
+ config?: boolean;
54
+ /**
55
+ * Caught errors throughout the pipeline. Unlike other categories, defaults to `true` even when `debug` is unspecified. Explicitly set `errors: false` or `debug: false` to silence.
56
+ */
57
+ errors?: boolean;
58
+ /**
59
+ * Outgoing call metadata (provider, model, message/tool counts) emitted before each adapter SDK call.
60
+ */
61
+ request?: boolean;
62
+ }
63
+ /**
64
+ * Granular debug configuration combining per-category toggles with an optional custom logger. Any unspecified category flag defaults to `true`.
65
+ */
66
+ export interface DebugConfig extends DebugCategories {
67
+ /**
68
+ * Custom `Logger` implementation. When omitted, a default `ConsoleLogger` routes output to `console.debug`/`info`/`warn`/`error`.
69
+ */
70
+ logger?: Logger;
71
+ }
72
+ /**
73
+ * The shape accepted by the `debug` option on every `@tanstack/ai` activity. Pass `true` to enable all categories with the default console logger; `false` to silence everything including errors; an object for granular control.
74
+ */
75
+ export type DebugOption = boolean | DebugConfig;
@@ -1,4 +1,5 @@
1
1
  import { StandardJSONSchemaV1 } from '@standard-schema/spec';
2
+ import { InternalLogger } from './logger/internal-logger.js';
2
3
  import { BaseEvent as AGUIBaseEvent, CustomEvent as AGUICustomEvent, MessagesSnapshotEvent as AGUIMessagesSnapshotEvent, ReasoningEncryptedValueEvent as AGUIReasoningEncryptedValueEvent, ReasoningEndEvent as AGUIReasoningEndEvent, ReasoningMessageContentEvent as AGUIReasoningMessageContentEvent, ReasoningMessageEndEvent as AGUIReasoningMessageEndEvent, ReasoningMessageStartEvent as AGUIReasoningMessageStartEvent, ReasoningStartEvent as AGUIReasoningStartEvent, RunErrorEvent as AGUIRunErrorEvent, RunFinishedEvent as AGUIRunFinishedEvent, RunStartedEvent as AGUIRunStartedEvent, StateDeltaEvent as AGUIStateDeltaEvent, StateSnapshotEvent as AGUIStateSnapshotEvent, StepFinishedEvent as AGUIStepFinishedEvent, StepStartedEvent as AGUIStepStartedEvent, TextMessageContentEvent as AGUITextMessageContentEvent, TextMessageEndEvent as AGUITextMessageEndEvent, TextMessageStartEvent as AGUITextMessageStartEvent, ToolCallArgsEvent as AGUIToolCallArgsEvent, ToolCallEndEvent as AGUIToolCallEndEvent, ToolCallResultEvent as AGUIToolCallResultEvent, ToolCallStartEvent as AGUIToolCallStartEvent, EventType } from '@ag-ui/core';
3
4
  /**
4
5
  * Tool call states - track the lifecycle of a tool call
@@ -604,6 +605,12 @@ export interface TextOptions<TProviderOptionsSuperset extends Record<string, any
604
605
  * @see https://developer.mozilla.org/en-US/docs/Web/API/AbortController
605
606
  */
606
607
  abortController?: AbortController;
608
+ /**
609
+ * Internal logger threaded from the chat entry point. Adapter implementations
610
+ * must call `logger.request()` before SDK calls, `logger.provider()` for each
611
+ * chunk received, and `logger.errors()` in catch blocks.
612
+ */
613
+ logger: InternalLogger;
607
614
  /**
608
615
  * Thread ID for AG-UI protocol run correlation.
609
616
  * When provided, this will be used in RunStartedEvent and RunFinishedEvent.
@@ -959,6 +966,11 @@ export interface SummarizationOptions {
959
966
  maxLength?: number;
960
967
  style?: 'bullet-points' | 'paragraph' | 'concise';
961
968
  focus?: Array<string>;
969
+ /**
970
+ * Internal logger threaded from the summarize() entry point. Adapters must
971
+ * call logger.request() before the SDK call and logger.errors() in catch blocks.
972
+ */
973
+ logger: InternalLogger;
962
974
  }
963
975
  export interface SummarizationResult {
964
976
  id: string;
@@ -985,6 +997,11 @@ export interface ImageGenerationOptions<TProviderOptions extends object = object
985
997
  size?: TSize;
986
998
  /** Model-specific options for image generation */
987
999
  modelOptions?: TProviderOptions;
1000
+ /**
1001
+ * Internal logger threaded from the generateImage() entry point. Adapters must
1002
+ * call logger.request() before the SDK call and logger.errors() in catch blocks.
1003
+ */
1004
+ logger: InternalLogger;
988
1005
  }
989
1006
  /**
990
1007
  * A single generated image
@@ -1031,6 +1048,11 @@ export interface VideoGenerationOptions<TProviderOptions extends object = object
1031
1048
  duration?: number;
1032
1049
  /** Model-specific options for video generation */
1033
1050
  modelOptions?: TProviderOptions;
1051
+ /**
1052
+ * Internal logger threaded from the generateVideo() entry point. Adapters must
1053
+ * call logger.request() before the SDK call and logger.errors() in catch blocks.
1054
+ */
1055
+ logger: InternalLogger;
1034
1056
  }
1035
1057
  /**
1036
1058
  * Result of creating a video generation job.
@@ -1088,6 +1110,12 @@ export interface TTSOptions<TProviderOptions extends object = object> {
1088
1110
  speed?: number;
1089
1111
  /** Model-specific options for TTS generation */
1090
1112
  modelOptions?: TProviderOptions;
1113
+ /**
1114
+ * Internal logger threaded from the generateSpeech() entry point. Adapters
1115
+ * must call logger.request() before the SDK call and logger.errors() in
1116
+ * catch blocks.
1117
+ */
1118
+ logger: InternalLogger;
1091
1119
  }
1092
1120
  /**
1093
1121
  * Result of text-to-speech generation.
@@ -1123,6 +1151,12 @@ export interface TranscriptionOptions<TProviderOptions extends object = object>
1123
1151
  responseFormat?: 'json' | 'text' | 'srt' | 'verbose_json' | 'vtt';
1124
1152
  /** Model-specific options for transcription */
1125
1153
  modelOptions?: TProviderOptions;
1154
+ /**
1155
+ * Internal logger threaded from the generateTranscription() entry point.
1156
+ * Adapters must call logger.request() before the SDK call and logger.errors()
1157
+ * in catch blocks.
1158
+ */
1159
+ logger: InternalLogger;
1126
1160
  }
1127
1161
  /**
1128
1162
  * A single segment of transcribed audio with timing information.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/ai",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "Core TanStack AI library - Open source AI SDK",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -24,6 +24,10 @@
24
24
  "./middlewares": {
25
25
  "types": "./dist/esm/middlewares/index.d.ts",
26
26
  "import": "./dist/esm/middlewares/index.js"
27
+ },
28
+ "./adapter-internals": {
29
+ "types": "./dist/esm/adapter-internals.d.ts",
30
+ "import": "./dist/esm/adapter-internals.js"
27
31
  }
28
32
  },
29
33
  "sideEffects": false,
@@ -47,7 +51,7 @@
47
51
  "dependencies": {
48
52
  "@ag-ui/core": "0.0.49",
49
53
  "partial-json": "^0.1.7",
50
- "@tanstack/ai-event-client": "0.2.6"
54
+ "@tanstack/ai-event-client": "0.2.7"
51
55
  },
52
56
  "devDependencies": {
53
57
  "@standard-schema/spec": "^1.1.0",
@@ -3,9 +3,9 @@ name: ai-core
3
3
  description: >
4
4
  Entry point for TanStack AI skills. Routes to chat-experience, tool-calling,
5
5
  media-generation, structured-outputs, adapter-configuration, ag-ui-protocol,
6
- middleware, and custom-backend-integration. Use chat() not streamText(),
7
- openaiText() not createOpenAI(), toServerSentEventsResponse() not manual SSE,
8
- middleware hooks not onEnd callbacks.
6
+ middleware, custom-backend-integration, and debug-logging. Use chat() not
7
+ streamText(), openaiText() not createOpenAI(), toServerSentEventsResponse()
8
+ not manual SSE, middleware hooks not onEnd callbacks.
9
9
  type: core
10
10
  library: tanstack-ai
11
11
  library_version: '0.10.0'
@@ -31,6 +31,7 @@ Always import from the framework package on the client — never from
31
31
  | Implement AG-UI streaming protocol server-side | ai-core/ag-ui-protocol/SKILL.md |
32
32
  | Add analytics, logging, or lifecycle hooks | ai-core/middleware/SKILL.md |
33
33
  | Connect to a non-TanStack-AI backend | ai-core/custom-backend-integration/SKILL.md |
34
+ | Turn on/off debug logging, pipe into pino/winston | ai-core/debug-logging/SKILL.md |
34
35
  | Set up Code Mode (LLM code execution) | See `@tanstack/ai-code-mode` package skills |
35
36
 
36
37
  ## Quick Decision Tree
@@ -43,6 +44,7 @@ Always import from the framework package on the client — never from
43
44
  - Building a server-only AG-UI backend? → ai-core/ag-ui-protocol
44
45
  - Adding analytics or post-stream events? → ai-core/middleware
45
46
  - Connecting to a custom backend? → ai-core/custom-backend-integration
47
+ - Turning on debug logging to trace chunks/tools/middleware? → ai-core/debug-logging
46
48
  - Debugging mistakes? → Check Common Mistakes in the relevant sub-skill
47
49
 
48
50
  ## Critical Rules
@@ -0,0 +1,263 @@
1
+ ---
2
+ name: ai-core/debug-logging
3
+ description: >
4
+ Pluggable, category-toggleable debug logging for TanStack AI activities.
5
+ Toggle with `debug: true | false | DebugConfig` on chat(), summarize(),
6
+ generateImage(), generateSpeech(), generateTranscription(), generateVideo().
7
+ Categories: request, provider, output, middleware, tools, agentLoop,
8
+ config, errors. Pipe into pino/winston/etc via `debug: { logger }`. Errors
9
+ log by default even when `debug` is omitted; silence with `debug: false`.
10
+ type: sub-skill
11
+ library: tanstack-ai
12
+ library_version: '0.10.0'
13
+ sources:
14
+ - 'TanStack/ai:docs/advanced/debug-logging.md'
15
+ ---
16
+
17
+ # Debug Logging
18
+
19
+ > **Dependency note:** This skill builds on ai-core. Read it first for critical rules.
20
+
21
+ Use this skill when you need to turn debug logging on or off, narrow what's
22
+ printed, or pipe logs into a custom logger (pino, winston, etc.). The same
23
+ `debug` option works on every activity — `chat()`, `summarize()`,
24
+ `generateImage()`, `generateSpeech()`, `generateTranscription()`,
25
+ `generateVideo()`.
26
+
27
+ ## Turn it on
28
+
29
+ ```typescript
30
+ import { chat } from '@tanstack/ai'
31
+ import { openaiText } from '@tanstack/ai-openai'
32
+
33
+ const stream = chat({
34
+ adapter: openaiText('gpt-5.2'),
35
+ messages,
36
+ debug: true, // all categories on, prints to console
37
+ })
38
+ ```
39
+
40
+ Each log line is prefixed with an emoji and `[tanstack-ai:<category>]`:
41
+
42
+ ```
43
+ 📤 [tanstack-ai:request] 📤 activity=chat provider=openai model=gpt-5.2 messages=1 tools=0 stream=true
44
+ 🔁 [tanstack-ai:agentLoop] 🔁 run started
45
+ 📥 [tanstack-ai:provider] 📥 provider=openai type=response.output_text.delta
46
+ 📨 [tanstack-ai:output] 📨 type=TEXT_MESSAGE_CONTENT
47
+ ```
48
+
49
+ ## Turn it off
50
+
51
+ ```typescript
52
+ chat({
53
+ adapter: openaiText('gpt-5.2'),
54
+ messages,
55
+ debug: false, // silence everything, including errors
56
+ })
57
+ ```
58
+
59
+ Omitting `debug` is **not** the same as `debug: false`. When omitted, the
60
+ `errors` category is still on (errors are cheap and important). Use
61
+ `debug: false` or `debug: { errors: false }` for true silence.
62
+
63
+ ## `DebugOption` — the accepted shapes
64
+
65
+ ```typescript
66
+ type DebugOption = boolean | DebugConfig
67
+
68
+ interface DebugConfig {
69
+ // Per-category flags. Any flag omitted from a DebugConfig defaults to true.
70
+ request?: boolean
71
+ provider?: boolean
72
+ output?: boolean
73
+ middleware?: boolean
74
+ tools?: boolean
75
+ agentLoop?: boolean
76
+ config?: boolean
77
+ errors?: boolean
78
+ // Optional custom logger. Defaults to ConsoleLogger.
79
+ logger?: Logger
80
+ }
81
+ ```
82
+
83
+ Resolution rules for the `debug?: DebugOption` field on every activity:
84
+
85
+ | `debug` value | Effect |
86
+ | --------------------- | ---------------------------------------------------------------------------- |
87
+ | omitted (`undefined`) | Only `errors` is active; default `ConsoleLogger`. |
88
+ | `true` | All categories on; default `ConsoleLogger`. |
89
+ | `false` | All categories off (including `errors`); default `ConsoleLogger`. |
90
+ | `DebugConfig` object | Each unspecified flag defaults to `true`; `logger` replaces `ConsoleLogger`. |
91
+
92
+ ## Narrow what's printed
93
+
94
+ Pass a `DebugConfig` object. Unspecified categories default to `true`, so it's
95
+ easiest to toggle by setting specific flags to `false`:
96
+
97
+ ```typescript
98
+ chat({
99
+ adapter: openaiText('gpt-5.2'),
100
+ messages,
101
+ debug: { middleware: false }, // everything except middleware
102
+ })
103
+ ```
104
+
105
+ To print only a specific set, set the rest to `false` explicitly:
106
+
107
+ ```typescript
108
+ chat({
109
+ adapter: openaiText('gpt-5.2'),
110
+ messages,
111
+ debug: {
112
+ provider: true,
113
+ output: true,
114
+ middleware: false,
115
+ tools: false,
116
+ agentLoop: false,
117
+ config: false,
118
+ errors: true, // keep errors on — they're cheap and important
119
+ request: false,
120
+ },
121
+ })
122
+ ```
123
+
124
+ ## Pipe into your own logger
125
+
126
+ ```typescript
127
+ import type { Logger } from '@tanstack/ai'
128
+ import pino from 'pino'
129
+
130
+ const pinoLogger = pino()
131
+ const logger: Logger = {
132
+ debug: (msg, meta) => pinoLogger.debug(meta, msg),
133
+ info: (msg, meta) => pinoLogger.info(meta, msg),
134
+ warn: (msg, meta) => pinoLogger.warn(meta, msg),
135
+ error: (msg, meta) => pinoLogger.error(meta, msg),
136
+ }
137
+
138
+ chat({
139
+ adapter: openaiText('gpt-5.2'),
140
+ messages,
141
+ debug: { logger }, // all categories on, piped to pino
142
+ })
143
+ ```
144
+
145
+ The default console logger is exported as `ConsoleLogger` if you want to wrap
146
+ it:
147
+
148
+ ```typescript
149
+ import { ConsoleLogger } from '@tanstack/ai'
150
+ ```
151
+
152
+ ## Categories
153
+
154
+ | Category | Logs | Applies to |
155
+ | ------------ | -------------------------------------------------------------- | ------------------------------------- |
156
+ | `request` | Outgoing call to a provider (model, message count, tool count) | All activities |
157
+ | `provider` | Every raw chunk/frame received from a provider SDK | Streaming activities (chat, realtime) |
158
+ | `output` | Every chunk or result yielded to the caller | All activities |
159
+ | `middleware` | Inputs and outputs around every middleware hook | `chat()` only |
160
+ | `tools` | Before/after tool call execution | `chat()` only |
161
+ | `agentLoop` | Agent-loop iterations and phase transitions | `chat()` only |
162
+ | `config` | Config transforms returned by middleware `onConfig` hooks | `chat()` only |
163
+ | `errors` | Every caught error anywhere in the pipeline | All activities |
164
+
165
+ Chat-only categories simply never fire for non-chat activities — those
166
+ concepts don't exist in their pipelines.
167
+
168
+ ## Non-chat activities
169
+
170
+ Same `debug` option everywhere:
171
+
172
+ ```typescript
173
+ summarize({ adapter, text, debug: true })
174
+ generateImage({ adapter, prompt: 'a cat', debug: { logger } })
175
+ generateSpeech({ adapter, text, debug: { request: true } })
176
+ generateTranscription({ adapter, audio, debug: false })
177
+ generateVideo({ adapter, prompt: 'a wave', debug: { output: true } })
178
+ ```
179
+
180
+ Realtime session adapters in provider packages (e.g. `openaiRealtime`,
181
+ `elevenlabsRealtime`) accept the same `debug?: DebugOption` on their session
182
+ options. They emit `request`, `provider`, and `errors` lines; the chat-only
183
+ categories don't apply.
184
+
185
+ ## Common Mistakes
186
+
187
+ ### a. HIGH: Treating omitted `debug` as silent
188
+
189
+ ```typescript
190
+ // WRONG — expecting this to be completely silent
191
+ chat({ adapter, messages })
192
+ // Errors still print via [tanstack-ai:errors] ... on failure.
193
+
194
+ // CORRECT — explicit silence
195
+ chat({ adapter, messages, debug: false })
196
+ chat({ adapter, messages, debug: { errors: false } })
197
+ ```
198
+
199
+ `debug` undefined means "only errors"; `debug: false` means "nothing at all".
200
+
201
+ Source: docs/advanced/debug-logging.md
202
+
203
+ ### b. MEDIUM: Reaching for middleware when `debug` would do
204
+
205
+ ```typescript
206
+ // WRONG — writing logging middleware to see chunks flow
207
+ const chunkLogger: ChatMiddleware = {
208
+ name: 'chunk-logger',
209
+ onChunk: (ctx, chunk) => {
210
+ console.log(chunk.type, chunk)
211
+ },
212
+ }
213
+ chat({ adapter, messages, middleware: [chunkLogger] })
214
+
215
+ // CORRECT — just turn on the relevant categories
216
+ chat({
217
+ adapter,
218
+ messages,
219
+ debug: { provider: true, output: true },
220
+ })
221
+ ```
222
+
223
+ For observing the built-in pipeline, the `debug` option is strictly faster
224
+ than writing logging middleware. Reach for middleware when you need to
225
+ _transform_ chunks, not just see them.
226
+
227
+ Source: docs/advanced/debug-logging.md
228
+
229
+ ### c. LOW: Logger implementation that can throw
230
+
231
+ A user-supplied `Logger` that throws will have its exception swallowed by the
232
+ SDK so it never masks the real error that triggered the log call. Still,
233
+ prefer implementations that don't throw — silenced exceptions are harder to
234
+ debug than loud ones.
235
+
236
+ ```typescript
237
+ // WRONG — a logger that can throw on serialization
238
+ const fragile: Logger = {
239
+ debug: (msg, meta) => console.debug(msg, JSON.stringify(meta)), // cyclic meta → throws
240
+ /* ... */
241
+ }
242
+
243
+ // CORRECT — guard serialization in the logger itself
244
+ const safe: Logger = {
245
+ debug: (msg, meta) => {
246
+ try {
247
+ console.debug(msg, meta)
248
+ } catch {
249
+ console.debug(msg)
250
+ }
251
+ },
252
+ /* ... */
253
+ }
254
+ ```
255
+
256
+ Source: packages/typescript/ai/src/logger/internal-logger.ts
257
+
258
+ ## Cross-References
259
+
260
+ - See also: **ai-core/middleware/SKILL.md** — if you need to transform
261
+ chunks/config, not just observe them.
262
+ - See also: **Observability** (`docs/advanced/observability.md`) — the
263
+ programmatic event client for a richer, structured feed beyond log lines.
@@ -18,7 +18,12 @@ export interface TextAdapterConfig {
18
18
  }
19
19
 
20
20
  /**
21
- * Options for structured output generation
21
+ * Options for structured output generation.
22
+ *
23
+ * The internal logger is threaded through `chatOptions.logger` (inherited from
24
+ * `TextOptions`). Adapter implementations must call `logger.request()` before
25
+ * SDK calls, `logger.provider()` for each chunk received, and `logger.errors()`
26
+ * in catch blocks.
22
27
  */
23
28
  export interface StructuredOutputOptions<TProviderOptions extends object> {
24
29
  /** Text options for the request */