UNPKG

@tanstack/ai

Version:

Core TanStack AI library - Open source AI SDK

108 lines (94 loc) 3.75 kB
import type { DebugCategories, Logger } from './types' /** * Fully-resolved categories map. Every flag is a definite boolean (never * undefined), produced by `resolveDebugOption` from a `DebugOption`. */ export type ResolvedCategories = Required<DebugCategories> /** * Package-internal logger wrapper used by every activity and adapter in * `@tanstack/ai`. Wraps a user-supplied (or default `ConsoleLogger`) `Logger` * plus a fully-resolved per-category map. Each category has a dedicated * method that no-ops when its flag is `false`, or prepends a * `[tanstack-ai:<category>] ` prefix and calls the underlying logger's * `error` (for the `errors` category) or `debug` (for everything else). * * Not exported from the package root. Adapter packages consume it via the * `@tanstack/ai/adapter-internals` subpath export. */ /** * Emoji marker per category — bracketing the `[tanstack-ai:<cat>]` tag on * both sides makes it trivial to visually pick out a category when scanning * dense streaming logs. */ const CATEGORY_EMOJI: Record<keyof ResolvedCategories, string> = { request: '📤', provider: '📥', output: '📨', middleware: '🧩', tools: '🔧', agentLoop: '🔁', config: '⚙️', errors: '❌', } export class InternalLogger { constructor( private readonly logger: Logger, private readonly categories: ResolvedCategories, ) {} /** Whether a category is enabled. Cheap, safe to call on hot paths. */ isEnabled(category: keyof ResolvedCategories): boolean { return this.categories[category] } private emit( level: 'debug' | 'error', category: keyof ResolvedCategories, message: string, meta?: Record<string, unknown>, ): void { if (!this.categories[category]) return const emoji = CATEGORY_EMOJI[category] const prefixed = `${emoji} [tanstack-ai:${category}] ${emoji} ${message}` try { if (level === 'error') this.logger.error(prefixed, meta) else this.logger.debug(prefixed, meta) } catch { // User-supplied logger threw; swallow so we never mask the original // error that triggered this log call. } } /** Log a raw chunk/frame received from a provider SDK. */ provider(message: string, meta?: Record<string, unknown>): void { this.emit('debug', 'provider', message, meta) } /** Log a chunk/result yielded to the consumer after middleware. */ output(message: string, meta?: Record<string, unknown>): void { this.emit('debug', 'output', message, meta) } /** Log inputs/outputs around a middleware hook invocation. Chat-only. */ middleware(message: string, meta?: Record<string, unknown>): void { this.emit('debug', 'middleware', message, meta) } /** Log before/after a tool-call execution. Chat-only. */ tools(message: string, meta?: Record<string, unknown>): void { this.emit('debug', 'tools', message, meta) } /** Log an agent-loop iteration marker or phase transition. Chat-only. */ agentLoop(message: string, meta?: Record<string, unknown>): void { this.emit('debug', 'agentLoop', message, meta) } /** Log a config transform returned by a middleware `onConfig` hook. Chat-only. */ config(message: string, meta?: Record<string, unknown>): void { this.emit('debug', 'config', message, meta) } /** * Log a caught error. Defaults to on even when `debug` is unspecified. * Uses the underlying logger's `error` level. */ errors(message: string, meta?: Record<string, unknown>): void { this.emit('error', 'errors', message, meta) } /** Log outgoing request metadata before an adapter SDK call. */ request(message: string, meta?: Record<string, unknown>): void { this.emit('debug', 'request', message, meta) } }