@zerotal/ai 1.6.3 → 1.7.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.
package/api-surface.md ADDED
@@ -0,0 +1,620 @@
1
+ # @zerotal/ai — public API surface
2
+
3
+ <!-- AUTO-GENERATED by scripts/api-surface.ts. Do not edit by hand.
4
+ Run `bun run api:surface` to regenerate after an intentional API change. -->
5
+
6
+ ## . `(./src/index.ts)`
7
+
8
+ class AiAgentLimitError = {
9
+ new (message: string, context?: Record<string, unknown>): AiAgentLimitError
10
+ readonly code: string
11
+ readonly context?: Record<string, unknown> | undefined
12
+ readonly status: number
13
+ }
14
+
15
+ class AiCancelledError = {
16
+ new (message?: string): AiCancelledError
17
+ readonly code: string
18
+ readonly context?: Record<string, unknown> | undefined
19
+ readonly status: number
20
+ }
21
+
22
+ class AiConfigError = {
23
+ new (message: string, context?: Record<string, unknown>): AiConfigError
24
+ readonly code: string
25
+ readonly context?: Record<string, unknown> | undefined
26
+ readonly status: number
27
+ }
28
+
29
+ class AiDriverUnavailableError = {
30
+ new (driver: string, packageName: string): AiDriverUnavailableError
31
+ readonly code: string
32
+ readonly context?: Record<string, unknown> | undefined
33
+ readonly status: number
34
+ }
35
+
36
+ class AiError = {
37
+ new (message: string, code?: string, status?: number, context?: Record<string, unknown>): AiError
38
+ readonly code: string
39
+ readonly context?: Record<string, unknown> | undefined
40
+ readonly status: number
41
+ }
42
+
43
+ class AiFake = {
44
+ new (_app: Application, _original: Binding): AiFake
45
+ static install: () => AiFake
46
+ agent: (request: AiAgentRequest) => Promise<AiAgentResult>
47
+ assertNotPrompted: (expected: string | RegExp | ((prompt: string) => boolean)) => void
48
+ assertNothingPrompted: () => void
49
+ assertPromptCount: (count: number) => void
50
+ assertPrompted: (expected: string | RegExp | ((prompt: string) => boolean)) => void
51
+ assertSystemPrompted: (expected: string | RegExp | ((prompt: string) => boolean)) => void
52
+ calls: CapturedGeneration[]
53
+ countTokens: (request: AiRequest | string) => Promise<number>
54
+ drivers: () => string[]
55
+ embed: (input: string | string[], _options?: Omit<AiEmbedRequest, 'input'>) => Promise<AiEmbedResponse>
56
+ generate: (request: AiRequest | string) => Promise<AiResponse>
57
+ handlerFor: (name: string) => AiQueueHandler | undefined
58
+ object: <T = Record<string, unknown>>(request: AiRequest | string) => Promise<T>
59
+ onGenerated: (name: string, handler: AiQueueHandler) => AiFake
60
+ prompts: string[]
61
+ queue: (request: AiRequest, options: AiQueueOptions) => Promise<void>
62
+ refuse: (category?: string | null, explanation?: string | null) => AiFake
63
+ respondWith: (...texts: string[]) => AiFake
64
+ respondWithObject: (...objects: unknown[]) => AiFake
65
+ restore: () => void
66
+ stream: (request: AiRequest | string) => AsyncIterable<AiStreamChunk>
67
+ text: (request: AiRequest | string) => Promise<string>
68
+ verify: () => Promise<DriverStatus>
69
+ }
70
+
71
+ class AiGenerated = {
72
+ new (driver: string, model: string, operation: string, inputTokens: number, outputTokens: number, cacheReadTokens: number, durationMs: number, costUsd: number, ok: boolean, preview: string, error?: string | undefined): AiGenerated
73
+ readonly cacheReadTokens: number
74
+ readonly costUsd: number
75
+ readonly driver: string
76
+ readonly durationMs: number
77
+ readonly error?: string | undefined
78
+ readonly inputTokens: number
79
+ readonly model: string
80
+ readonly ok: boolean
81
+ readonly operation: string
82
+ readonly outputTokens: number
83
+ readonly preview: string
84
+ }
85
+
86
+ class AiGenerationJob = {
87
+ new (request: AiRequest, options: AiQueueOptions): AiGenerationJob
88
+ static fromPayload: (data: Record<string, unknown>) => AiGenerationJob
89
+ _chain: SerializedJob[] | undefined
90
+ batchId: string | undefined
91
+ className: string
92
+ debounceKey: () => string
93
+ handle: () => Promise<void>
94
+ payload: () => Record<string, unknown>
95
+ readonly debounce?: number
96
+ readonly maxAttempts: number
97
+ readonly queue: string
98
+ readonly retryDelay: number
99
+ }
100
+
101
+ class AiManager = {
102
+ new (config: AiConfigShape): AiManager
103
+ agent: (request: AiAgentRequest) => Promise<AiAgentResult>
104
+ countTokens: (request: AiRequest | string) => Promise<number>
105
+ driver: (name?: string) => AiDriver
106
+ drivers: () => string[]
107
+ embed: (input: string | string[], options?: Omit<AiEmbedRequest, 'input'>) => Promise<AiEmbedResponse>
108
+ embeddingsDriver: (name?: string) => EmbeddingsDriver
109
+ extend: (name: string, factory: DriverResolver) => AiManager
110
+ extendEmbeddings: (name: string, factory: EmbeddingsResolver) => AiManager
111
+ generate: (request: AiRequest | string) => Promise<AiResponse>
112
+ handlerFor: (name: string) => AiQueueHandler | undefined
113
+ object: <T = Record<string, unknown>>(request: AiRequest | string, schema: SchemaInput | ((rule: RuleBuilder) => SchemaInput)) => Promise<T>
114
+ onGenerated: (name: string, handler: AiQueueHandler) => AiManager
115
+ queue: (request: AiRequest, options: AiQueueOptions) => Promise<void>
116
+ readonly config: AiConfigShape
117
+ stream: (request: AiRequest | string) => AsyncIterable<AiStreamChunk>
118
+ text: (request: AiRequest | string) => Promise<string>
119
+ verify: (name?: string) => Promise<DriverStatus>
120
+ }
121
+
122
+ class AiProvider = {
123
+ new (app: Application): AiProvider
124
+ static dependsOn?: (new (app: Application) => ServiceProvider)[]
125
+ static environments: AppEnvironment[]
126
+ static priority?: number
127
+ static provides: readonly ['ai']
128
+ devProcesses: () => DevProcessDefinition[]
129
+ doctorChecks: () => DoctorCheck[]
130
+ onBooted: () => Promise<void>
131
+ onBooting: () => Promise<void>
132
+ onRegister: () => void
133
+ onRequestProcessed: (_ctx: HttpContext) => Promise<void>
134
+ onRequestReceived: (_ctx: HttpContext) => Promise<void>
135
+ onResponseSent: (_ctx: HttpContext) => Promise<void>
136
+ onStarted: () => Promise<void>
137
+ onStarting: () => Promise<void>
138
+ onStopped: () => Promise<void>
139
+ onStopping: () => Promise<void>
140
+ replContext: () => Record<string, unknown>
141
+ }
142
+
143
+ class AiRateLimitError = {
144
+ new (message: string, retryAfterSeconds?: number | undefined): AiRateLimitError
145
+ readonly code: string
146
+ readonly context?: Record<string, unknown> | undefined
147
+ readonly retryAfterSeconds?: number | undefined
148
+ readonly status: number
149
+ }
150
+
151
+ class AiRefused = {
152
+ new (driver: string, model: string, category: string | null, preview: string): AiRefused
153
+ readonly category: string | null
154
+ readonly driver: string
155
+ readonly model: string
156
+ readonly preview: string
157
+ }
158
+
159
+ class AiRefusedError = {
160
+ new (category: string | null, explanation: string | null, partialText?: string): AiRefusedError
161
+ readonly category: string | null
162
+ readonly code: string
163
+ readonly context?: Record<string, unknown> | undefined
164
+ readonly explanation: string | null
165
+ readonly partialText: string
166
+ readonly status: number
167
+ }
168
+
169
+ class AiRequestError = {
170
+ new (message: string, providerStatus: number, context?: Record<string, unknown>): AiRequestError
171
+ readonly code: string
172
+ readonly context?: Record<string, unknown> | undefined
173
+ readonly providerStatus: number
174
+ readonly status: number
175
+ }
176
+
177
+ class AiSchemaError = {
178
+ new (message: string, context?: Record<string, unknown>): AiSchemaError
179
+ readonly code: string
180
+ readonly context?: Record<string, unknown> | undefined
181
+ readonly status: number
182
+ }
183
+
184
+ class AiSpendCommand = {
185
+ new (): AiSpendCommand
186
+ static args: ArgDef[]
187
+ static commandName: string
188
+ static description: string
189
+ static flags: FlagDef[]
190
+ static needsApp: boolean
191
+ _readLine: () => Promise<string>
192
+ _writer: OutputWriter
193
+ app: unknown
194
+ args: Record<string, string>
195
+ ask: (question: string, defaultValue?: string) => Promise<string>
196
+ choice: (question: string, options: string[]) => Promise<string>
197
+ confirm: (question: string, defaultValue?: boolean) => Promise<boolean>
198
+ dim: (msg: string) => void
199
+ error: (msg: string) => void
200
+ flags: Record<string, string | number | boolean>
201
+ info: (msg: string) => void
202
+ line: (msg: string) => void
203
+ newLine: () => void
204
+ run: () => Promise<void>
205
+ secret: (question: string) => Promise<string>
206
+ section: (title: string) => void
207
+ table: (rows: [string, string][], indent?: number) => void
208
+ warn: (msg: string) => void
209
+ write: (msg: string) => void
210
+ }
211
+
212
+ class AiSpendLimitError = {
213
+ new (message: string, context?: Record<string, unknown>): AiSpendLimitError
214
+ readonly code: string
215
+ readonly context?: Record<string, unknown> | undefined
216
+ readonly status: number
217
+ }
218
+
219
+ class AiTestCommand = {
220
+ new (): AiTestCommand
221
+ static args: ArgDef[]
222
+ static commandName: string
223
+ static description: string
224
+ static flags: FlagDef[]
225
+ static needsApp: boolean
226
+ _readLine: () => Promise<string>
227
+ _writer: OutputWriter
228
+ app: unknown
229
+ args: Record<string, string>
230
+ ask: (question: string, defaultValue?: string) => Promise<string>
231
+ choice: (question: string, options: string[]) => Promise<string>
232
+ confirm: (question: string, defaultValue?: boolean) => Promise<boolean>
233
+ dim: (msg: string) => void
234
+ error: (msg: string) => void
235
+ flags: Record<string, string | number | boolean>
236
+ info: (msg: string) => void
237
+ line: (msg: string) => void
238
+ newLine: () => void
239
+ run: () => Promise<void>
240
+ secret: (question: string) => Promise<string>
241
+ section: (title: string) => void
242
+ table: (rows: [string, string][], indent?: number) => void
243
+ warn: (msg: string) => void
244
+ write: (msg: string) => void
245
+ }
246
+
247
+ class AiToolCalled = {
248
+ new (driver: string, tool: string, step: number, durationMs: number, ok: boolean, error?: string | undefined): AiToolCalled
249
+ readonly driver: string
250
+ readonly durationMs: number
251
+ readonly error?: string | undefined
252
+ readonly ok: boolean
253
+ readonly step: number
254
+ readonly tool: string
255
+ }
256
+
257
+ class AnthropicDriver = {
258
+ new (config: AnthropicConfigShape, inject?: LoadedAnthropic): AnthropicDriver
259
+ countTokens: (request: AiRequest) => Promise<number>
260
+ model: string
261
+ object: <T>(request: AiRequest, schema: SchemaInput) => Promise<AiObjectResponse<T>>
262
+ readonly name: 'anthropic'
263
+ stream: (request: AiRequest) => AsyncIterable<AiStreamChunk>
264
+ text: (request: AiRequest) => Promise<AiResponse>
265
+ verify: () => Promise<DriverStatus>
266
+ }
267
+
268
+ class OllamaDriver = {
269
+ new (config: OllamaConfigShape, fetchImpl?: typeof fetch): OllamaDriver
270
+ countTokens: (_request: AiRequest) => Promise<number>
271
+ model: string
272
+ object: <T>(request: AiRequest, schema: SchemaInput) => Promise<AiObjectResponse<T>>
273
+ readonly name: 'ollama'
274
+ stream: (request: AiRequest) => AsyncIterable<AiStreamChunk>
275
+ text: (request: AiRequest) => Promise<AiResponse>
276
+ verify: () => Promise<DriverStatus>
277
+ }
278
+
279
+ class OllamaEmbeddingsDriver = {
280
+ new (config: { model: string; baseUrl: string; timeout: number; }, fetchImpl?: typeof fetch): OllamaEmbeddingsDriver
281
+ embed: (request: AiEmbedRequest) => Promise<AiEmbedResponse>
282
+ model: string
283
+ readonly name: 'ollama'
284
+ }
285
+
286
+ class OpenAiDriver = {
287
+ new (config: OpenAiConfigShape, fetchImpl?: typeof fetch): OpenAiDriver
288
+ countTokens: (_request: AiRequest) => Promise<number>
289
+ model: string
290
+ object: <T>(request: AiRequest, schema: SchemaInput) => Promise<AiObjectResponse<T>>
291
+ readonly name: 'openai'
292
+ stream: (request: AiRequest) => AsyncIterable<AiStreamChunk>
293
+ text: (request: AiRequest) => Promise<AiResponse>
294
+ verify: () => Promise<DriverStatus>
295
+ }
296
+
297
+ class OpenAiEmbeddingsDriver = {
298
+ new (config: { apiKey: string; model: string; baseUrl: string; timeout: number; }, fetchImpl?: typeof fetch): OpenAiEmbeddingsDriver
299
+ embed: (request: AiEmbedRequest) => Promise<AiEmbedResponse>
300
+ model: string
301
+ readonly name: 'openai'
302
+ }
303
+
304
+ class UnknownAiDriverError = {
305
+ new (driver: string, known?: string[]): UnknownAiDriverError
306
+ readonly code: string
307
+ readonly context?: Record<string, unknown> | undefined
308
+ readonly status: number
309
+ }
310
+
311
+ const Ai = AiManager
312
+
313
+ function AiConfig = (options?: DeepPartial<AiConfigShape>) => AiConfigShape
314
+
315
+ function AiConfigFromEnv = () => AiConfigShape
316
+
317
+ function estimateCost = (model: string, usage: AiUsage) => number
318
+
319
+ function modelPrice = (model: string) => ModelPrice | undefined
320
+
321
+ function modelRejectsSampling = (model: string) => boolean
322
+
323
+ function modelStats = () => ModelStat[]
324
+
325
+ function recentGenerations = (limit?: number) => AiDelivery[]
326
+
327
+ function refusalRate = () => number
328
+
329
+ function registerModelPrice = (model: string, price: ModelPrice) => void
330
+
331
+ function resetSpend = () => void
332
+
333
+ function resetStats = () => void
334
+
335
+ function spentToday = () => number
336
+
337
+ function strippedConstraints = (input: SchemaInput) => string[]
338
+
339
+ function tool = <I extends Record<string, unknown> = Record<string, unknown>>(options: { name: string; description: string; input: ((rule: RuleBuilder) => Record<string, FieldRule>) | SchemaInput; handle: (input: I, ctx: AiToolContext) => Promise<unknown> | unknown;}) => AiTool
340
+
341
+ function toSchema = (input: SchemaInput) => Schema
342
+
343
+ function translateSchema = (input: SchemaInput) => JsonSchema
344
+
345
+ function validateAiConfig = (config: AiConfigShape) => void
346
+
347
+ interface AgentOptions = {
348
+ maxResumes: number
349
+ maxSteps: number
350
+ signal: AbortSignal
351
+ }
352
+
353
+ interface AiAgentConfigShape = {
354
+ lock: boolean
355
+ lockTtl: number
356
+ maxResumes: number
357
+ maxSteps: number
358
+ }
359
+
360
+ interface AiAgentRequest = {
361
+ cache?: boolean
362
+ driver?: string
363
+ effort?: AiEffort
364
+ lock?: string
365
+ maxResumes?: number
366
+ maxSteps?: number
367
+ maxTokens?: number
368
+ messages?: AiMessage[]
369
+ model?: string
370
+ prompt?: string
371
+ providerOptions?: AiProviderOptions
372
+ signal?: AbortSignal
373
+ system?: string
374
+ temperature?: number
375
+ tools?: AiTool<Record<string, unknown>>[]
376
+ }
377
+
378
+ interface AiAgentResult = {
379
+ model: string
380
+ steps: AiAgentStep[]
381
+ stopReason: AiStopReason
382
+ text: string
383
+ usage: AiUsage
384
+ }
385
+
386
+ interface AiAgentStep = {
387
+ call: AiToolCall
388
+ durationMs: number
389
+ isError: boolean
390
+ result: string
391
+ step: number
392
+ }
393
+
394
+ interface AiConfigShape = {
395
+ agent: AiAgentConfigShape
396
+ default: string
397
+ drivers: { anthropic?: AnthropicConfigShape; openai?: OpenAiConfigShape; ollama?: OllamaConfigShape;}
398
+ embeddings: EmbeddingsConfigShape
399
+ limits: AiLimitsConfigShape
400
+ redact: boolean
401
+ }
402
+
403
+ interface AiDelivery = {
404
+ at: number
405
+ cacheReadTokens: number
406
+ costUsd: number
407
+ driver: string
408
+ durationMs: number
409
+ error?: string
410
+ inputTokens: number
411
+ model: string
412
+ ok: boolean
413
+ operation: string
414
+ outputTokens: number
415
+ preview: string
416
+ refused: boolean
417
+ }
418
+
419
+ interface AiDriver = {
420
+ agent?: (request: AiRequest, options: AgentOptions) => Promise<AiAgentResult>
421
+ countTokens: (request: AiRequest) => Promise<number>
422
+ object: <T>(request: AiRequest, schema: SchemaInput) => Promise<AiObjectResponse<T>>
423
+ readonly model: string
424
+ readonly name: string
425
+ stream: (request: AiRequest) => AsyncIterable<AiStreamChunk>
426
+ text: (request: AiRequest) => Promise<AiResponse>
427
+ verify: () => Promise<DriverStatus>
428
+ }
429
+
430
+ interface AiEmbedRequest = {
431
+ driver?: string
432
+ input: string | string[]
433
+ model?: string
434
+ signal?: AbortSignal
435
+ }
436
+
437
+ interface AiEmbedResponse = {
438
+ embeddings: number[][]
439
+ model: string
440
+ usage: Pick<AiUsage, 'inputTokens'>
441
+ }
442
+
443
+ interface AiLimitsConfigShape = {
444
+ perDayUsd: number
445
+ perRequestUsd: number
446
+ }
447
+
448
+ interface AiMessage = {
449
+ content: string
450
+ raw?: unknown
451
+ role: AiRole
452
+ toolCalls?: AiToolCall[]
453
+ toolResults?: AiToolResult[]
454
+ }
455
+
456
+ interface AiObjectResponse = {
457
+ model: string
458
+ object: T
459
+ raw?: unknown
460
+ usage: AiUsage
461
+ }
462
+
463
+ interface AiQueueOptions = {
464
+ handler: string
465
+ meta?: Record<string, unknown>
466
+ queue?: string
467
+ }
468
+
469
+ interface AiRequest = {
470
+ cache?: boolean
471
+ driver?: string
472
+ effort?: AiEffort
473
+ maxTokens?: number
474
+ messages?: AiMessage[]
475
+ model?: string
476
+ prompt?: string
477
+ providerOptions?: AiProviderOptions
478
+ signal?: AbortSignal
479
+ system?: string
480
+ temperature?: number
481
+ tools?: AiTool<Record<string, unknown>>[]
482
+ }
483
+
484
+ interface AiResponse = {
485
+ assistantTurn: AiMessage
486
+ model: string
487
+ raw?: unknown
488
+ stopReason: AiStopReason
489
+ text: string
490
+ toolCalls: AiToolCall[]
491
+ usage: AiUsage
492
+ }
493
+
494
+ interface AiTool = {
495
+ description: string
496
+ handler: (input: I, ctx: AiToolContext) => Promise<unknown> | unknown
497
+ inputSchema: JsonSchema
498
+ name: string
499
+ }
500
+
501
+ interface AiToolCall = {
502
+ id: string
503
+ input: Record<string, unknown>
504
+ name: string
505
+ }
506
+
507
+ interface AiToolContext = {
508
+ signal: AbortSignal
509
+ step: number
510
+ }
511
+
512
+ interface AiToolResult = {
513
+ content: string
514
+ id: string
515
+ isError?: boolean
516
+ }
517
+
518
+ interface AiUsage = {
519
+ cacheReadTokens: number
520
+ cacheWriteTokens: number
521
+ inputTokens: number
522
+ outputTokens: number
523
+ }
524
+
525
+ interface AnthropicConfigShape = {
526
+ apiKey: string
527
+ baseUrl?: string
528
+ cacheSystem: boolean
529
+ effort: AiEffort
530
+ fallbacks: boolean
531
+ maxTokens: number
532
+ model: string
533
+ streamMaxTokens: number
534
+ temperature?: number
535
+ timeout: number
536
+ }
537
+
538
+ interface CapturedGeneration = {
539
+ operation: string
540
+ prompt: string
541
+ request: AiRequest
542
+ system: string | undefined
543
+ }
544
+
545
+ interface DriverStatus = {
546
+ detail: string
547
+ model: string
548
+ ok: boolean
549
+ }
550
+
551
+ interface EmbeddingsConfigShape = {
552
+ default: string
553
+ drivers: { openai?: { apiKey: string; model: string; baseUrl: string; timeout: number; }; ollama?: { model: string; baseUrl: string; timeout: number; };}
554
+ }
555
+
556
+ interface EmbeddingsDriver = {
557
+ embed: (request: AiEmbedRequest) => Promise<AiEmbedResponse>
558
+ readonly model: string
559
+ readonly name: string
560
+ }
561
+
562
+ interface JsonSchema = {
563
+ additionalProperties?: false
564
+ anyOf?: JsonSchema[]
565
+ description?: string
566
+ enum?: (string | number)[]
567
+ format?: string
568
+ items?: JsonSchema
569
+ properties?: Record<string, JsonSchema>
570
+ required?: string[]
571
+ type?: 'string' | 'number' | 'boolean' | 'object' | 'array' | 'integer' | 'null'
572
+ }
573
+
574
+ interface ModelPrice = {
575
+ input: number
576
+ output: number
577
+ }
578
+
579
+ interface ModelStat = {
580
+ cacheReadTokens: number
581
+ calls: number
582
+ costUsd: number
583
+ failures: number
584
+ inputTokens: number
585
+ model: string
586
+ outputTokens: number
587
+ p50: number
588
+ p95: number
589
+ refusals: number
590
+ }
591
+
592
+ interface OllamaConfigShape = {
593
+ baseUrl: string
594
+ model: string
595
+ timeout: number
596
+ }
597
+
598
+ interface OpenAiConfigShape = {
599
+ apiKey: string
600
+ baseUrl: string
601
+ maxTokens: number
602
+ model: string
603
+ timeout: number
604
+ }
605
+
606
+ type AiConfigInput = { default?: string | undefined; drivers?: DeepPartial<{ anthropic?: AnthropicConfigShape; openai?: OpenAiConfigShape; ollama?: OllamaConfigShape; }> | undefined; embeddings?: DeepPartial<EmbeddingsConfigShape> | undefined; limits?: DeepPartial<AiLimitsConfigShape> | undefined; redact?: boolean | undefined; agent?: DeepPartial<AiAgentConfigShape> | undefined;}
607
+
608
+ type AiEffort = 'max' | 'medium' | 'low' | 'high' | 'xhigh'
609
+
610
+ type AiProviderOptions = { [x: string]: Record<string, unknown>;}
611
+
612
+ type AiQueueHandler = (response: AiResponse, meta: Record<string, unknown>) => Promise<void> | void
613
+
614
+ type AiRole = 'user' | 'assistant'
615
+
616
+ type AiStopReason = 'end_turn' | 'max_tokens' | 'tool_use' | 'pause_turn' | 'refusal' | 'stop_sequence' | 'unknown'
617
+
618
+ type AiStreamChunk = { type: 'text'; text: string;} | { type: 'thinking'; text: string;} | { type: 'tool_call'; call: AiToolCall;} | { type: 'done'; response: AiResponse;}
619
+
620
+ type SchemaInput = { [x: string]: FieldRuleDefinition | FieldRule;}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zerotal/ai",
3
- "version": "1.6.3",
3
+ "version": "1.7.0",
4
4
  "license": "MIT",
5
5
  "maturity": "experimental",
6
6
  "private": false,
@@ -12,6 +12,7 @@
12
12
  },
13
13
  "files": [
14
14
  "CHANGELOG.md",
15
+ "api-surface.md",
15
16
  "src",
16
17
  "!src/**/*.test.ts",
17
18
  "!src/**/*.test.tsx",
@@ -29,9 +30,9 @@
29
30
  "typecheck": "tsc --noEmit"
30
31
  },
31
32
  "dependencies": {
32
- "@zerotal/core": "1.6.3",
33
- "@zerotal/validator": "1.6.3",
34
- "@zerotal/queue": "1.6.3"
33
+ "@zerotal/core": "1.7.0",
34
+ "@zerotal/validator": "1.7.0",
35
+ "@zerotal/queue": "1.7.0"
35
36
  },
36
37
  "peerDependencies": {
37
38
  "@anthropic-ai/sdk": ">=0.70.0"
package/src/config.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { deepMerge } from "@zerotal/core";
2
+ import type { DeepPartial } from "@zerotal/core";
2
3
  import { AiConfigError } from "./errors.ts";
3
4
  import type {
4
5
  AiConfigShape,
@@ -9,20 +10,6 @@ import type {
9
10
  } from "./types.ts";
10
11
  import { modelRejectsSampling } from "./pricing.ts";
11
12
 
12
- /**
13
- * Recursively-optional view of the config, so callers override only what they
14
- * care about.
15
- *
16
- * `NonNullable` before the `extends object` test is load-bearing: every driver
17
- * block is already optional, so `AnthropicConfigShape | undefined` does not
18
- * extend `object` and the recursion would stop one level too early — leaving
19
- * `{ drivers: { anthropic: { apiKey } } }`, the single most common thing anyone
20
- * writes in `config/ai.ts`, a type error.
21
- */
22
- type DeepPartial<T> = {
23
- [K in keyof T]?: NonNullable<T[K]> extends object ? DeepPartial<NonNullable<T[K]>> : T[K];
24
- };
25
-
26
13
  /**
27
14
  * What {@link AiConfig} accepts — every key optional, all the way down. The
28
15
  * same type the factory's parameter is written as, exported under a name