universal-llm-client 4.2.0 → 4.5.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 (108) hide show
  1. package/CHANGELOG.md +142 -103
  2. package/LICENSE +21 -21
  3. package/README.md +640 -591
  4. package/dist/ai-model.d.ts +12 -1
  5. package/dist/ai-model.d.ts.map +1 -1
  6. package/dist/ai-model.js +36 -1
  7. package/dist/ai-model.js.map +1 -1
  8. package/dist/gemma-channel.d.ts +14 -0
  9. package/dist/gemma-channel.d.ts.map +1 -0
  10. package/dist/gemma-channel.js +38 -0
  11. package/dist/gemma-channel.js.map +1 -0
  12. package/dist/gemma-diffusion.d.ts +49 -0
  13. package/dist/gemma-diffusion.d.ts.map +1 -0
  14. package/dist/gemma-diffusion.js +147 -0
  15. package/dist/gemma-diffusion.js.map +1 -0
  16. package/dist/http.d.ts +4 -0
  17. package/dist/http.d.ts.map +1 -1
  18. package/dist/http.js +14 -1
  19. package/dist/http.js.map +1 -1
  20. package/dist/index.d.ts +2 -1
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +4 -0
  23. package/dist/index.js.map +1 -1
  24. package/dist/interfaces.d.ts +183 -7
  25. package/dist/interfaces.d.ts.map +1 -1
  26. package/dist/interfaces.js.map +1 -1
  27. package/dist/providers/anthropic.d.ts.map +1 -1
  28. package/dist/providers/anthropic.js +28 -3
  29. package/dist/providers/anthropic.js.map +1 -1
  30. package/dist/providers/google.d.ts +22 -1
  31. package/dist/providers/google.d.ts.map +1 -1
  32. package/dist/providers/google.js +225 -13
  33. package/dist/providers/google.js.map +1 -1
  34. package/dist/providers/ollama.d.ts +2 -0
  35. package/dist/providers/ollama.d.ts.map +1 -1
  36. package/dist/providers/ollama.js +59 -30
  37. package/dist/providers/ollama.js.map +1 -1
  38. package/dist/providers/openai.d.ts +14 -0
  39. package/dist/providers/openai.d.ts.map +1 -1
  40. package/dist/providers/openai.js +200 -22
  41. package/dist/providers/openai.js.map +1 -1
  42. package/dist/router.d.ts +2 -0
  43. package/dist/router.d.ts.map +1 -1
  44. package/dist/router.js +4 -0
  45. package/dist/router.js.map +1 -1
  46. package/dist/stream-decoder.d.ts +12 -0
  47. package/dist/stream-decoder.d.ts.map +1 -1
  48. package/dist/stream-decoder.js +182 -5
  49. package/dist/stream-decoder.js.map +1 -1
  50. package/dist/thinking.d.ts +36 -0
  51. package/dist/thinking.d.ts.map +1 -0
  52. package/dist/thinking.js +52 -0
  53. package/dist/thinking.js.map +1 -0
  54. package/package.json +118 -116
  55. package/src/ai-model.ts +400 -350
  56. package/src/auditor.ts +213 -213
  57. package/src/client.ts +402 -402
  58. package/src/debug/debug-google-streaming.ts +1 -1
  59. package/src/demos/basic/universal-llm-examples.ts +3 -3
  60. package/src/demos/diffusion-gemma/.env +29 -0
  61. package/src/demos/diffusion-gemma/.env.example +27 -0
  62. package/src/demos/diffusion-gemma/CLAUDE.md +95 -0
  63. package/src/demos/diffusion-gemma/README.md +59 -0
  64. package/src/demos/diffusion-gemma/canvas.ts +1606 -0
  65. package/src/demos/diffusion-gemma/docker-compose.yml +29 -0
  66. package/src/demos/diffusion-gemma/probe-stream.ts +51 -0
  67. package/src/demos/diffusion-gemma/probe-tools.ts +55 -0
  68. package/src/demos/diffusion-gemma/server.ts +1205 -0
  69. package/src/demos/diffusion-gemma/start-vllm.sh +98 -0
  70. package/src/gemma-channel.ts +47 -0
  71. package/src/gemma-diffusion.ts +167 -0
  72. package/src/http.ts +261 -247
  73. package/src/index.ts +180 -161
  74. package/src/interfaces.ts +843 -657
  75. package/src/mcp.ts +345 -345
  76. package/src/providers/anthropic.ts +796 -762
  77. package/src/providers/google.ts +840 -620
  78. package/src/providers/index.ts +8 -8
  79. package/src/providers/ollama.ts +503 -469
  80. package/src/providers/openai.ts +587 -392
  81. package/src/router.ts +785 -780
  82. package/src/stream-decoder.ts +535 -361
  83. package/src/structured-output.ts +759 -759
  84. package/src/test-scripts/test-google-deep-research.ts +33 -0
  85. package/src/test-scripts/test-google-streaming-enhanced.ts +147 -147
  86. package/src/test-scripts/test-google-streaming.ts +1 -1
  87. package/src/test-scripts/test-google-system-prompt-comprehensive.ts +189 -189
  88. package/src/test-scripts/test-google-thinking.ts +46 -0
  89. package/src/test-scripts/test-system-message-positions.ts +163 -163
  90. package/src/test-scripts/test-system-prompt-improvement-demo.ts +83 -83
  91. package/src/test-scripts/test-vllm-qwen36.ts +256 -0
  92. package/src/tests/ai-model.test.ts +1614 -1614
  93. package/src/tests/auditor.test.ts +224 -224
  94. package/src/tests/gemma-diffusion.test.ts +115 -0
  95. package/src/tests/http.test.ts +200 -200
  96. package/src/tests/interfaces.test.ts +117 -117
  97. package/src/tests/providers/anthropic.test.ts +118 -0
  98. package/src/tests/providers/google.test.ts +841 -660
  99. package/src/tests/providers/ollama.test.ts +1034 -954
  100. package/src/tests/providers/openai.test.ts +1511 -1122
  101. package/src/tests/router.test.ts +254 -254
  102. package/src/tests/stream-decoder.test.ts +263 -179
  103. package/src/tests/structured-output.test.ts +1450 -1450
  104. package/src/tests/thinking.test.ts +65 -0
  105. package/src/tests/tools.test.ts +175 -175
  106. package/src/thinking.ts +73 -0
  107. package/src/tools.ts +246 -246
  108. package/src/zod-adapter.ts +72 -72
package/src/auditor.ts CHANGED
@@ -1,213 +1,213 @@
1
- /**
2
- * Universal LLM Client v3 — Auditor (Observability)
3
- *
4
- * Every LLM interaction (request, response, tool call, retry, failover)
5
- * is recorded through the Auditor interface. Frameworks inject their own
6
- * Auditor for dashboards, cost tracking, or behavioral scoring.
7
- */
8
-
9
- import type { TokenUsageInfo, ToolExecutionResult } from './interfaces.js';
10
-
11
- // ============================================================================
12
- // Audit Event
13
- // ============================================================================
14
-
15
- export type AuditEventType =
16
- | 'request'
17
- | 'response'
18
- | 'stream_start'
19
- | 'stream_end'
20
- | 'tool_call'
21
- | 'tool_result'
22
- | 'error'
23
- | 'retry'
24
- | 'failover'
25
- | 'structured_request'
26
- | 'structured_response'
27
- | 'structured_validation_error';
28
-
29
- export interface AuditEvent {
30
- /** Unix timestamp in ms */
31
- timestamp: number;
32
- /** Event type */
33
- type: AuditEventType;
34
- /** Provider that generated this event */
35
- provider?: string;
36
- /** Model name */
37
- model?: string;
38
- /** Duration in ms (for request/response pairs) */
39
- duration?: number;
40
- /** Token usage (for response events) */
41
- usage?: TokenUsageInfo;
42
- /** Tool execution details (for tool_call/tool_result events) */
43
- toolExecution?: ToolExecutionResult;
44
- /** Error message (for error/retry events) */
45
- error?: string;
46
- /** Arbitrary metadata for framework-specific data */
47
- metadata?: Record<string, unknown>;
48
- /** Schema name for structured output events */
49
- schemaName?: string;
50
- /** Raw output snippet for validation errors */
51
- rawOutput?: string;
52
- }
53
-
54
- // ============================================================================
55
- // Auditor Interface
56
- // ============================================================================
57
-
58
- /**
59
- * Interface for LLM observability.
60
- *
61
- * Implement this to capture all LLM lifecycle events.
62
- * The library calls `record()` at every interaction point.
63
- */
64
- export interface Auditor {
65
- /** Record an audit event */
66
- record(event: AuditEvent): void;
67
- /** Flush any buffered events (optional) */
68
- flush?(): Promise<void>;
69
- }
70
-
71
- // ============================================================================
72
- // Built-in Auditors
73
- // ============================================================================
74
-
75
- /**
76
- * Zero-overhead auditor that discards all events.
77
- * Used as the default when no auditor is configured.
78
- */
79
- export class NoopAuditor implements Auditor {
80
- record(_event: AuditEvent): void {
81
- // Intentionally empty
82
- }
83
- }
84
-
85
- /**
86
- * Structured console logging auditor.
87
- * Useful for development and debugging.
88
- */
89
- export class ConsoleAuditor implements Auditor {
90
- private prefix: string;
91
-
92
- constructor(prefix: string = '[LLM]') {
93
- this.prefix = prefix;
94
- }
95
-
96
- record(event: AuditEvent): void {
97
- const parts = [
98
- this.prefix,
99
- event.type.toUpperCase(),
100
- event.provider ? `[${event.provider}]` : '',
101
- event.model ? `(${event.model})` : '',
102
- ].filter(Boolean);
103
-
104
- switch (event.type) {
105
- case 'request':
106
- console.log(parts.join(' '), '→');
107
- break;
108
- case 'response':
109
- console.log(
110
- parts.join(' '),
111
- event.duration ? `${event.duration}ms` : '',
112
- event.usage ? `${event.usage.totalTokens} tokens` : '',
113
- );
114
- break;
115
- case 'stream_start':
116
- console.log(parts.join(' '), 'streaming...');
117
- break;
118
- case 'stream_end':
119
- console.log(
120
- parts.join(' '),
121
- 'done',
122
- event.duration ? `${event.duration}ms` : '',
123
- );
124
- break;
125
- case 'tool_call':
126
- console.log(parts.join(' '), event.toolExecution?.tool_call_id ?? '');
127
- break;
128
- case 'tool_result':
129
- console.log(
130
- parts.join(' '),
131
- event.toolExecution?.error ? '❌' : '✅',
132
- event.toolExecution?.duration ? `${event.toolExecution.duration}ms` : '',
133
- );
134
- break;
135
- case 'error':
136
- console.error(parts.join(' '), event.error ?? 'Unknown error');
137
- break;
138
- case 'retry':
139
- console.warn(parts.join(' '), event.error ?? '', event.metadata ?? '');
140
- break;
141
- case 'failover':
142
- console.warn(parts.join(' '), '→', event.metadata?.['nextProvider'] ?? '');
143
- break;
144
- case 'structured_request':
145
- console.log(
146
- parts.join(' '),
147
- `schema=${event.schemaName ?? 'unknown'}`,
148
- '→',
149
- );
150
- break;
151
- case 'structured_response':
152
- console.log(
153
- parts.join(' '),
154
- event.duration ? `${event.duration}ms` : '',
155
- `schema=${event.schemaName ?? 'unknown'}`,
156
- );
157
- break;
158
- case 'structured_validation_error':
159
- console.error(
160
- parts.join(' '),
161
- `schema=${event.schemaName ?? 'unknown'}`,
162
- event.error ?? 'Validation failed',
163
- event.rawOutput ? `raw=${event.rawOutput.slice(0, 50)}...` : '',
164
- );
165
- break;
166
- }
167
- }
168
- }
169
-
170
- /**
171
- * Buffered auditor that collects events for batch processing.
172
- * Useful for custom sinks (OpenTelemetry, DataDog, databases, etc.)
173
- */
174
- export class BufferedAuditor implements Auditor {
175
- private events: AuditEvent[] = [];
176
- private maxBufferSize: number;
177
- private onFlush?: (events: AuditEvent[]) => Promise<void>;
178
-
179
- constructor(options: {
180
- maxBufferSize?: number;
181
- onFlush?: (events: AuditEvent[]) => Promise<void>;
182
- } = {}) {
183
- this.maxBufferSize = options.maxBufferSize ?? 1000;
184
- this.onFlush = options.onFlush;
185
- }
186
-
187
- record(event: AuditEvent): void {
188
- this.events.push(event);
189
- if (this.events.length >= this.maxBufferSize) {
190
- // Auto-flush when buffer is full (fire and forget)
191
- this.flush().catch(() => {});
192
- }
193
- }
194
-
195
- /** Get all buffered events */
196
- getEvents(): ReadonlyArray<AuditEvent> {
197
- return this.events;
198
- }
199
-
200
- /** Flush buffered events to the configured sink */
201
- async flush(): Promise<void> {
202
- if (this.events.length === 0) return;
203
- const batch = this.events.splice(0);
204
- if (this.onFlush) {
205
- await this.onFlush(batch);
206
- }
207
- }
208
-
209
- /** Clear all buffered events without flushing */
210
- clear(): void {
211
- this.events.length = 0;
212
- }
213
- }
1
+ /**
2
+ * Universal LLM Client v3 — Auditor (Observability)
3
+ *
4
+ * Every LLM interaction (request, response, tool call, retry, failover)
5
+ * is recorded through the Auditor interface. Frameworks inject their own
6
+ * Auditor for dashboards, cost tracking, or behavioral scoring.
7
+ */
8
+
9
+ import type { TokenUsageInfo, ToolExecutionResult } from './interfaces.js';
10
+
11
+ // ============================================================================
12
+ // Audit Event
13
+ // ============================================================================
14
+
15
+ export type AuditEventType =
16
+ | 'request'
17
+ | 'response'
18
+ | 'stream_start'
19
+ | 'stream_end'
20
+ | 'tool_call'
21
+ | 'tool_result'
22
+ | 'error'
23
+ | 'retry'
24
+ | 'failover'
25
+ | 'structured_request'
26
+ | 'structured_response'
27
+ | 'structured_validation_error';
28
+
29
+ export interface AuditEvent {
30
+ /** Unix timestamp in ms */
31
+ timestamp: number;
32
+ /** Event type */
33
+ type: AuditEventType;
34
+ /** Provider that generated this event */
35
+ provider?: string;
36
+ /** Model name */
37
+ model?: string;
38
+ /** Duration in ms (for request/response pairs) */
39
+ duration?: number;
40
+ /** Token usage (for response events) */
41
+ usage?: TokenUsageInfo;
42
+ /** Tool execution details (for tool_call/tool_result events) */
43
+ toolExecution?: ToolExecutionResult;
44
+ /** Error message (for error/retry events) */
45
+ error?: string;
46
+ /** Arbitrary metadata for framework-specific data */
47
+ metadata?: Record<string, unknown>;
48
+ /** Schema name for structured output events */
49
+ schemaName?: string;
50
+ /** Raw output snippet for validation errors */
51
+ rawOutput?: string;
52
+ }
53
+
54
+ // ============================================================================
55
+ // Auditor Interface
56
+ // ============================================================================
57
+
58
+ /**
59
+ * Interface for LLM observability.
60
+ *
61
+ * Implement this to capture all LLM lifecycle events.
62
+ * The library calls `record()` at every interaction point.
63
+ */
64
+ export interface Auditor {
65
+ /** Record an audit event */
66
+ record(event: AuditEvent): void;
67
+ /** Flush any buffered events (optional) */
68
+ flush?(): Promise<void>;
69
+ }
70
+
71
+ // ============================================================================
72
+ // Built-in Auditors
73
+ // ============================================================================
74
+
75
+ /**
76
+ * Zero-overhead auditor that discards all events.
77
+ * Used as the default when no auditor is configured.
78
+ */
79
+ export class NoopAuditor implements Auditor {
80
+ record(_event: AuditEvent): void {
81
+ // Intentionally empty
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Structured console logging auditor.
87
+ * Useful for development and debugging.
88
+ */
89
+ export class ConsoleAuditor implements Auditor {
90
+ private prefix: string;
91
+
92
+ constructor(prefix: string = '[LLM]') {
93
+ this.prefix = prefix;
94
+ }
95
+
96
+ record(event: AuditEvent): void {
97
+ const parts = [
98
+ this.prefix,
99
+ event.type.toUpperCase(),
100
+ event.provider ? `[${event.provider}]` : '',
101
+ event.model ? `(${event.model})` : '',
102
+ ].filter(Boolean);
103
+
104
+ switch (event.type) {
105
+ case 'request':
106
+ console.log(parts.join(' '), '→');
107
+ break;
108
+ case 'response':
109
+ console.log(
110
+ parts.join(' '),
111
+ event.duration ? `${event.duration}ms` : '',
112
+ event.usage ? `${event.usage.totalTokens} tokens` : '',
113
+ );
114
+ break;
115
+ case 'stream_start':
116
+ console.log(parts.join(' '), 'streaming...');
117
+ break;
118
+ case 'stream_end':
119
+ console.log(
120
+ parts.join(' '),
121
+ 'done',
122
+ event.duration ? `${event.duration}ms` : '',
123
+ );
124
+ break;
125
+ case 'tool_call':
126
+ console.log(parts.join(' '), event.toolExecution?.tool_call_id ?? '');
127
+ break;
128
+ case 'tool_result':
129
+ console.log(
130
+ parts.join(' '),
131
+ event.toolExecution?.error ? '❌' : '✅',
132
+ event.toolExecution?.duration ? `${event.toolExecution.duration}ms` : '',
133
+ );
134
+ break;
135
+ case 'error':
136
+ console.error(parts.join(' '), event.error ?? 'Unknown error');
137
+ break;
138
+ case 'retry':
139
+ console.warn(parts.join(' '), event.error ?? '', event.metadata ?? '');
140
+ break;
141
+ case 'failover':
142
+ console.warn(parts.join(' '), '→', event.metadata?.['nextProvider'] ?? '');
143
+ break;
144
+ case 'structured_request':
145
+ console.log(
146
+ parts.join(' '),
147
+ `schema=${event.schemaName ?? 'unknown'}`,
148
+ '→',
149
+ );
150
+ break;
151
+ case 'structured_response':
152
+ console.log(
153
+ parts.join(' '),
154
+ event.duration ? `${event.duration}ms` : '',
155
+ `schema=${event.schemaName ?? 'unknown'}`,
156
+ );
157
+ break;
158
+ case 'structured_validation_error':
159
+ console.error(
160
+ parts.join(' '),
161
+ `schema=${event.schemaName ?? 'unknown'}`,
162
+ event.error ?? 'Validation failed',
163
+ event.rawOutput ? `raw=${event.rawOutput.slice(0, 50)}...` : '',
164
+ );
165
+ break;
166
+ }
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Buffered auditor that collects events for batch processing.
172
+ * Useful for custom sinks (OpenTelemetry, DataDog, databases, etc.)
173
+ */
174
+ export class BufferedAuditor implements Auditor {
175
+ private events: AuditEvent[] = [];
176
+ private maxBufferSize: number;
177
+ private onFlush?: (events: AuditEvent[]) => Promise<void>;
178
+
179
+ constructor(options: {
180
+ maxBufferSize?: number;
181
+ onFlush?: (events: AuditEvent[]) => Promise<void>;
182
+ } = {}) {
183
+ this.maxBufferSize = options.maxBufferSize ?? 1000;
184
+ this.onFlush = options.onFlush;
185
+ }
186
+
187
+ record(event: AuditEvent): void {
188
+ this.events.push(event);
189
+ if (this.events.length >= this.maxBufferSize) {
190
+ // Auto-flush when buffer is full (fire and forget)
191
+ this.flush().catch(() => {});
192
+ }
193
+ }
194
+
195
+ /** Get all buffered events */
196
+ getEvents(): ReadonlyArray<AuditEvent> {
197
+ return this.events;
198
+ }
199
+
200
+ /** Flush buffered events to the configured sink */
201
+ async flush(): Promise<void> {
202
+ if (this.events.length === 0) return;
203
+ const batch = this.events.splice(0);
204
+ if (this.onFlush) {
205
+ await this.onFlush(batch);
206
+ }
207
+ }
208
+
209
+ /** Clear all buffered events without flushing */
210
+ clear(): void {
211
+ this.events.length = 0;
212
+ }
213
+ }