@deepseek-ai/dsh-llm 0.0.1-rc.1

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.
@@ -0,0 +1,351 @@
1
+ /**
2
+ * LLM service: adapter registry with a waterfall-interceptable streaming call
3
+ * surface. Exports the `LlmService` default, the abstract `LlmAdapter` for
4
+ * provider backends, and `BlockAssembler` for chunk assembly.
5
+ *
6
+ * @module @deepseek-ai/dsh-llm
7
+ */
8
+ import { Context, Service } from '@deepseek-ai/cordis';
9
+ import type { GenerateOptions, LlmConfigurableProvider, LlmDiscoveredModel, LlmFailure, LlmModelContext, LlmModelDiscoveryRequest, LlmModelInfo, LlmResolvedModelInfo, LlmProviderInfo, StreamChunk } from './types.ts';
10
+ import type { ResolvedRetryPolicy } from './retry-policy.ts';
11
+ import type { ProviderRequestId } from './brand.ts';
12
+ import type { LlmCallConfig, LlmCallConfigAdapterDefaults } from './call-config.ts';
13
+ import { HarnessError } from './error.ts';
14
+ export * from './attribution.ts';
15
+ export * from './brand.ts';
16
+ export * from './never.ts';
17
+ export * from './error.ts';
18
+ export * from './api-key.ts';
19
+ export * from './types.ts';
20
+ export * from './content.ts';
21
+ export * from './message.ts';
22
+ export * from './retry-policy.ts';
23
+ export { BlockAssembler } from './assembler.ts';
24
+ export { callConfigEquals, deepFreeze, isAgentLoopRequest, markAgentLoopRequest } from './call-config.ts';
25
+ export type { LlmCallConfig, LlmCallConfigAdapterDefaults } from './call-config.ts';
26
+ declare module '@deepseek-ai/cordis' {
27
+ interface Context {
28
+ llm: LlmService;
29
+ }
30
+ interface Events {
31
+ /**
32
+ * Waterfall around every streaming model call (retry, replay, routing).
33
+ * Bound to the {@link LlmService}; call `next()` to reach the resolved
34
+ * adapter's stream, or yield your own chunks to short-circuit.
35
+ * @param options - the full request. A LOOP-built request carries the
36
+ * process-local {@link markAgentLoopRequest} identity and arrives deep-frozen
37
+ * (mutation throws): its content is a pure function of the session log (the
38
+ * reconstructability Agent Note), so listeners read it, never rewrite it.
39
+ * Hand-built calls do not carry that marker; their messages already obey
40
+ * the immutable creation contract.
41
+ * @mode waterfall
42
+ */
43
+ 'llm/stream'(this: LlmService, options: GenerateOptions, next: () => AsyncIterable<StreamChunk>): AsyncIterable<StreamChunk>;
44
+ /**
45
+ * The provider topology changed: an adapter registered or unregistered
46
+ * routes, or the configurable-provider directory gained or lost entries.
47
+ * This is a payload-free registry notification fired at each commit point
48
+ * (including registration disposal); consumers re-read `listProviders()`,
49
+ * `listModels()`, or `listConfigurableProviders()` for the new state.
50
+ * Observer failures are contained and cannot veto the registry mutation.
51
+ * @mode emit
52
+ */
53
+ 'llm/adapters-updated'(): void;
54
+ }
55
+ }
56
+ /** Structured provider facts and cause accepted by {@link LlmError}. */
57
+ export interface LlmErrorOptions extends ErrorOptions {
58
+ /** Valid HTTP status observed at the provider boundary. */
59
+ status?: number;
60
+ /** Positive finite provider-requested delay in milliseconds. */
61
+ providerRetryAfterMs?: number;
62
+ /** Non-empty opaque provider request id. */
63
+ requestId?: ProviderRequestId;
64
+ }
65
+ /**
66
+ * Typed error for LLM-related failures. Extends {@link HarnessError}, so the
67
+ * `code` string (e.g. `AUTH`, `RATE_LIMIT`, `NO_ADAPTER`) is shared taxonomy.
68
+ */
69
+ export declare class LlmError extends HarnessError {
70
+ /** Serializable facts retained beside this live Error. */
71
+ readonly failure: LlmFailure;
72
+ /**
73
+ * @param message - non-empty human-readable failure summary.
74
+ * @param code - non-empty stable provider-neutral machine code.
75
+ * @param options - optional cause and validated serializable provider facts.
76
+ */
77
+ constructor(message: string, code: string, options?: LlmErrorOptions);
78
+ }
79
+ /**
80
+ * Accept one supplied credential, or refuse it as unusable.
81
+ *
82
+ * A stored key arrives from the credentials seam, a `.env` line, or a shell
83
+ * export, all of which pick up surrounding whitespace, so trimming is silent.
84
+ * Anything else fails here rather than inside `fetch`, whose ByteString
85
+ * refusal names a UTF-16 code point instead of the setting to change. The key
86
+ * never enters the message: `ref` names where to fix it, and echoing any part
87
+ * of a secret into a log or a UI is the failure this diagnosis avoids.
88
+ *
89
+ * Lives beside {@link LlmError} rather than in `./api-key.ts` so the predicate
90
+ * module stays dependency-free; both adapters share this one diagnosis instead
91
+ * of keeping near-identical local copies.
92
+ * @param raw - the credential exactly as supplied.
93
+ * @param pkg - the refusing package name, prefixed to the diagnostic.
94
+ * @param ref - the credential reference the value resolved through.
95
+ * @returns the trimmed, usable key.
96
+ */
97
+ export declare function assertUsableApiKey(raw: string, pkg: string, ref: string): string;
98
+ /** One model call whose config and adapter registration were resolved together. */
99
+ export interface PreparedLlmCall {
100
+ /** Detached, deep-frozen config with any adapter-owned default materialized. */
101
+ readonly config: LlmCallConfig;
102
+ /** Immutable retry policy captured with the adapter registration. */
103
+ readonly retryPolicy: ResolvedRetryPolicy;
104
+ /** Detached context metadata resolved with the registration-bound call. */
105
+ readonly context?: LlmModelContext;
106
+ /** Config fields materialized by the captured adapter rather than proposed by the caller. */
107
+ readonly adapterDefaults: LlmCallConfigAdapterDefaults;
108
+ /**
109
+ * Dispatch this call once through the registration captured during
110
+ * preparation. The request's call-config fields must match {@link config};
111
+ * reuse or mismatch fails with `INVALID_PREPARED_CALL`.
112
+ * @param options - fully assembled request carrying the prepared config.
113
+ * @returns the chunk stream, including the `llm/stream` waterfall.
114
+ */
115
+ stream(options: GenerateOptions): AsyncIterable<StreamChunk>;
116
+ }
117
+ /**
118
+ * Provider-wire adapter for the harness message and stream vocabulary. Register implementations
119
+ * with `ctx.llm.registerAdapter(providers, adapter)`. Every provider HTTP request must include
120
+ * `attributionHeaders()`; prove the headers are added in the wire request or library header hook. The direct-fetch
121
+ * DeepSeek and library-backed pi-ai adapters meet this contract through different internals.
122
+ */
123
+ export declare abstract class LlmAdapter {
124
+ /**
125
+ * Describe one provider route owned by this adapter.
126
+ * @param provider - a route passed to `registerAdapter()` for this instance.
127
+ * @returns detached display metadata whose id must equal `provider`.
128
+ */
129
+ providerInfo(provider: string): LlmProviderInfo;
130
+ /**
131
+ * Return the provider-owned retry policy captured with this route.
132
+ * @param _provider - a route passed to `registerAdapter()` for this instance.
133
+ * @returns a resolved policy, or `undefined` to use the normal defaults.
134
+ */
135
+ providerRetryPolicy(_provider: string): ResolvedRetryPolicy | undefined;
136
+ /**
137
+ * List models this adapter can currently advertise for one owned provider.
138
+ * The result is advisory: an adapter may accept unlisted model ids, and
139
+ * consumers must not turn absence into request rejection.
140
+ * @param _provider - one provider route owned by this adapter.
141
+ * @returns discoverable models in adapter-preferred order.
142
+ */
143
+ listModels(_provider: string): Promise<readonly LlmModelInfo[]>;
144
+ /**
145
+ * Resolve all metadata available for one exact model. This query is
146
+ * independent of the advisory catalog and does not validate request routing.
147
+ * @param provider - one provider route owned by this adapter.
148
+ * @param model - exact model id passed to {@link GenerateOptions.model}.
149
+ * @param _signal - cancellation for this exact-model lookup; asynchronous
150
+ * implementations must settle promptly after it aborts.
151
+ * @returns provider/model identity plus any context, call-default, and reasoning metadata.
152
+ */
153
+ resolveModel(provider: string, model: string, _signal?: AbortSignal): Promise<LlmResolvedModelInfo>;
154
+ /**
155
+ * Stream one model call as raw chunks. The only required method.
156
+ * @param options - the fully-assembled request; implementations must honor `options.signal`.
157
+ * @returns the chunk stream, obeying the adapter contract documented on `StreamChunk`.
158
+ */
159
+ abstract stream(options: GenerateOptions): AsyncIterable<StreamChunk>;
160
+ }
161
+ /**
162
+ * What {@link LlmService.registerAdapter} returns: the disposer, plus an
163
+ * atomic route replacement for the same adapter instance.
164
+ */
165
+ export interface AdapterRegistrationHandle {
166
+ /** Release every route this registration currently holds. */
167
+ (): void;
168
+ /**
169
+ * Replace this registration's routes with `providers`, keeping the same
170
+ * adapter instance. The candidate set is validated in full first — a
171
+ * conflict with another adapter, an invalid name, or bad provider metadata
172
+ * throws and leaves the current routes untouched — and the swap itself is
173
+ * one synchronous section, so no request can observe a gap. An empty array
174
+ * is legal here (a settings section that emptied holds zero routes while
175
+ * staying registered), unlike an empty initial registration.
176
+ *
177
+ * Throws `LlmError` with code `REGISTRATION_DISPOSED` once the registration
178
+ * has been released: its routes are gone and its disposer has already run,
179
+ * so anything registered afterwards would have no owner left to release it.
180
+ * @param providers - the complete next route set for this registration.
181
+ */
182
+ replace(providers: string[]): void;
183
+ }
184
+ /**
185
+ * A live configurable-provider registration, disposable and atomically
186
+ * replaceable — the directory counterpart of {@link AdapterRegistrationHandle}.
187
+ */
188
+ export interface DirectoryRegistrationHandle {
189
+ /** Withdraw every entry this registration currently holds. */
190
+ (): void;
191
+ /**
192
+ * Replace this registration's entries with `entries`. The candidate set is
193
+ * validated in full first — an entry another registration already declares,
194
+ * a duplicate within the set, or invalid metadata throws and leaves the
195
+ * current entries untouched — and the swap is one synchronous section, so no
196
+ * reader observes a gap. An empty array is legal here, unlike an empty
197
+ * initial registration.
198
+ *
199
+ * Throws `LlmError` with code `REGISTRATION_DISPOSED` once the registration
200
+ * has been disposed.
201
+ */
202
+ replace(entries: readonly LlmConfigurableProvider[]): void;
203
+ }
204
+ /**
205
+ * The abstract `llm` service: an adapter registry plus a streaming model-call
206
+ * surface, interceptable via the `llm/stream` waterfall.
207
+ */
208
+ export declare class LlmService extends Service {
209
+ private adapters;
210
+ private directory;
211
+ private discoveries;
212
+ constructor(ctx: Context);
213
+ /** Notify topology observers without letting one broken listener veto the commit. */
214
+ private emitAdaptersUpdated;
215
+ /** Contained-listener diagnostic shared by the sync and async failure paths. */
216
+ private warnAdaptersListenerFailure;
217
+ /**
218
+ * Register an adapter for the given provider routes. Throws `LlmError` with code
219
+ * `DUPLICATE_ADAPTER` if any provider already has an adapter (all-or-nothing).
220
+ * Disposed with the fiber.
221
+ * @param providers - every provider route this adapter should serve.
222
+ * @param adapter - the adapter that streams calls for those providers.
223
+ * @returns the disposer, carrying {@link AdapterRegistrationHandle.replace}.
224
+ */
225
+ registerAdapter(providers: string[], adapter: LlmAdapter): AdapterRegistrationHandle;
226
+ /**
227
+ * Validate one candidate route set for `adapter`, treating routes this
228
+ * registration already holds as available. Nothing is mutated: a rejected
229
+ * candidate leaves the registry exactly as it was.
230
+ */
231
+ private prepareRoutes;
232
+ /**
233
+ * Swap this registration's routes for the prepared ones in one synchronous
234
+ * section, so no observer can see the registry between the release and the
235
+ * re-registration. The route set's one mutation point is also where
236
+ * `llm/adapters-updated` is published, so a `replace` announces itself
237
+ * exactly like a first registration.
238
+ */
239
+ private commitRoutes;
240
+ /**
241
+ * Describe provider routes with a registered adapter.
242
+ * @returns detached provider metadata in registration order.
243
+ */
244
+ listProviders(): LlmProviderInfo[];
245
+ /**
246
+ * Declare provider routes an adapter plugin can activate through
247
+ * configuration. Registration is all-or-nothing: an empty list, invalid
248
+ * entry, or a provider already declared by any registration throws
249
+ * `LlmError` without registering the rest. Disposed with the fiber.
250
+ * @param entries - every configurable provider this plugin owns.
251
+ * @returns a handle that withdraws all of them, and can atomically replace them.
252
+ */
253
+ registerConfigurableProviders(entries: readonly LlmConfigurableProvider[]): DirectoryRegistrationHandle;
254
+ /**
255
+ * List every declared configurable provider, registered or dormant.
256
+ * @returns detached directory entries in declaration order.
257
+ */
258
+ listConfigurableProviders(): LlmConfigurableProvider[];
259
+ /**
260
+ * Offer to interrogate provider endpoints on behalf of the settings
261
+ * namespace this plugin owns. The namespace is the key because that is what
262
+ * a configuration surface already holds from the configurable-provider
263
+ * directory, and because a provider being *added* has no route to name yet.
264
+ * Disposed with the fiber.
265
+ * @param settingsNs - the namespace whose profiles this discovery serves.
266
+ * @param discover - interrogates one endpoint; must honor `request.signal`.
267
+ * @returns the disposer that withdraws the offer.
268
+ */
269
+ registerModelDiscovery(settingsNs: string, discover: (request: LlmModelDiscoveryRequest) => Promise<readonly LlmDiscoveredModel[]>): () => void;
270
+ /**
271
+ * Interrogate one provider endpoint for the models it advertises. The
272
+ * request describes a draft, not a stored route, so nothing here reads or
273
+ * writes settings or credentials — the caller owns both, and the reply is
274
+ * candidate metadata a surface may offer for adoption.
275
+ * @param settingsNs - namespace whose registered discovery serves this draft.
276
+ * @param request - the endpoint, protocol, and one-shot credential to use.
277
+ * @returns the advertised models, deduplicated in endpoint order.
278
+ */
279
+ discoverModels(settingsNs: string, request: LlmModelDiscoveryRequest): Promise<LlmDiscoveredModel[]>;
280
+ /**
281
+ * Resolve the retry policy captured when one provider route was registered.
282
+ * @param provider - registered provider route to inspect.
283
+ * @returns the provider-owned policy, with normal defaults already resolved.
284
+ */
285
+ providerRetryPolicy(provider: string): ResolvedRetryPolicy;
286
+ /** Detach typed adapter-owned modality metadata. */
287
+ private detachedModalities;
288
+ /**
289
+ * Discover models advertised by one registered provider. Catalog membership
290
+ * is advisory and never changes routing or request validation.
291
+ * @param provider - registered provider route to inspect.
292
+ * @returns detached model metadata in adapter-preferred order.
293
+ */
294
+ listModels(provider: string): Promise<LlmModelInfo[]>;
295
+ /**
296
+ * Resolve and validate all metadata from the adapter that owns one exact
297
+ * route. The result is detached from adapter-owned objects; catalog
298
+ * membership remains advisory and does not control request routing.
299
+ * @param provider - registered provider route to inspect.
300
+ * @param model - exact model id passed to the adapter.
301
+ * @param signal - optional cancellation for adapter-owned asynchronous lookup.
302
+ * @returns exact model identity plus available context and reasoning metadata.
303
+ */
304
+ resolveModelInfo(provider: string, model: string, signal?: AbortSignal): Promise<LlmResolvedModelInfo>;
305
+ private resolveModelInfoFor;
306
+ /**
307
+ * Validate a conversation call config against its exact model capability and
308
+ * materialize adapter-configured defaults. Unsupported explicit efforts
309
+ * reject before provider I/O; no clamping or aliasing is performed. This
310
+ * standalone query does not bind a later dispatch; use {@link prepareCall}
311
+ * when logging and streaming must share one adapter registration.
312
+ * @param config - provider/model route and optional request controls.
313
+ * @param signal - optional cancellation for adapter-owned capability lookup.
314
+ * @returns a detached config only when a default must be materialized.
315
+ */
316
+ resolveCallConfig(config: LlmCallConfig, signal?: AbortSignal): Promise<LlmCallConfig>;
317
+ private resolveCallFor;
318
+ /**
319
+ * Resolve one call under its current adapter registration. The returned
320
+ * one-shot handle keeps that registration across header logging and dispatch,
321
+ * so HMR cannot combine one adapter's capability result with another adapter.
322
+ * @param config - provider/model route and optional request controls.
323
+ * @param signal - optional cancellation for adapter-owned capability lookup.
324
+ * @returns a prepared config and its registration-bound stream entry point.
325
+ */
326
+ prepareCall(config: LlmCallConfig, signal?: AbortSignal): Promise<PreparedLlmCall>;
327
+ private registration;
328
+ /** Remove replay state whose historical route is owned by another adapter. */
329
+ private forAdapter;
330
+ /**
331
+ * Final adapter boundary. Adapter selection, dispatch, iterator construction,
332
+ * and iteration failures become one terminal failure chunk. Middleware and
333
+ * downstream consumer failures remain thrown plugin or consumer errors.
334
+ */
335
+ private adapterStream;
336
+ /**
337
+ * Stream one model call as raw chunks (token-level deltas). Replay state is
338
+ * retained only when the same adapter instance owns its historical provider
339
+ * and the target provider. Final adapter selection remains fixed through
340
+ * asynchronous exact-model resolution and dispatch. Adapter selection,
341
+ * dispatch, and iteration failures become terminal `error` or `aborted`
342
+ * finish chunks; middleware, nested-call, cleanup, and consumer failures
343
+ * remain thrown.
344
+ * @param options - the full request; `options.provider` selects the adapter.
345
+ * @returns the chunk stream, possibly wrapped by `llm/stream` listeners.
346
+ */
347
+ stream(options: GenerateOptions): AsyncIterable<StreamChunk>;
348
+ private streamWithRegistration;
349
+ }
350
+ export default LlmService;
351
+ //# sourceMappingURL=index.d.ts.map