@xlaunch/llm 0.2.0-beta.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,430 @@
1
+ /**
2
+ * Canonical provider-neutral message and streaming vocabulary for the loop,
3
+ * session log, and plugins. Adapters alone translate provider wire messages;
4
+ * mapped interfaces make the content, source, and finish unions extensible.
5
+ */
6
+ import type { Branded } from '@xlaunch/brand';
7
+ import type { FileAttachmentRef, ImageAttachmentRef } from '@xlaunch/attachment';
8
+ import type { ToolCallId, ProviderRequestId, ReasoningEffortId } from './brand.ts';
9
+ import type { Message } from './message.ts';
10
+ declare module '@xlaunch/cordis' {
11
+ interface Events {
12
+ /**
13
+ * The provider topology changed: an adapter registered or unregistered
14
+ * routes, or the configurable-provider directory gained or lost entries.
15
+ * This payload-free registry notification fires at each commit point
16
+ * (including registration disposal); consumers re-read `listProviders()`,
17
+ * `listModels()`, or `listConfigurableProviders()` for the new state.
18
+ * Observer failures are contained and cannot veto the registry mutation.
19
+ * @mode emit
20
+ */
21
+ 'llm/adapters-updated'(): void;
22
+ }
23
+ }
24
+ export type { AssistantMessage, AssistantProvenance, Message, MessageSource, MessageSourceMap, ModelMessageSource, ToolMessageSource, ToolResultMessage, UserMessage, } from './message.ts';
25
+ /** Serializable provider or transport failure facts; policy decides whether they are retryable. */
26
+ export interface LlmFailure {
27
+ /** Human-readable provider or transport failure. */
28
+ readonly message: string;
29
+ /** Stable provider-neutral machine-routing code. */
30
+ readonly code: string;
31
+ /** HTTP status returned by the provider, when available. */
32
+ readonly status?: number;
33
+ /** Provider-requested delay in milliseconds, when valid and available. */
34
+ readonly providerRetryAfterMs?: number;
35
+ /** Opaque provider-issued request identifier for diagnostics. */
36
+ readonly requestId?: ProviderRequestId;
37
+ }
38
+ /** Plain text visible to the end user. */
39
+ export interface TextBlock {
40
+ type: 'text';
41
+ text: string;
42
+ }
43
+ /** Reasoning / thinking content, distinct from visible text. */
44
+ export interface ReasoningBlock {
45
+ type: 'reasoning';
46
+ text: string;
47
+ }
48
+ /**
49
+ * A durable raster image reference, valid in user or assistant content. The
50
+ * block is deliberately role-neutral; assistant-side rendering is forward
51
+ * compatibility — the current production adapters declare text-only output,
52
+ * so only user messages may carry images.
53
+ */
54
+ export interface ImageBlock {
55
+ type: 'image';
56
+ /** Immutable bytes and intrinsic display metadata owned by the attachment service. */
57
+ attachment: ImageAttachmentRef;
58
+ }
59
+ /**
60
+ * A durable verbatim file reference, valid in user content. Files never reach
61
+ * a provider natively: request assembly projects every occurrence to
62
+ * deterministic handle text (name, byte size, and the read-only saved path),
63
+ * so adapters and providers see text in its place while the durable log keeps
64
+ * the structured reference for presentation and authorization.
65
+ */
66
+ export interface FileBlock {
67
+ type: 'file';
68
+ /** Immutable verbatim bytes and display metadata owned by the attachment service. */
69
+ attachment: FileAttachmentRef;
70
+ }
71
+ /** A tool invocation requested by the model. */
72
+ export interface ToolCallBlock {
73
+ type: 'tool-call';
74
+ /** Provider-issued call id; correlates with the matching tool result. */
75
+ id: ToolCallId;
76
+ name: string;
77
+ /** Raw JSON string as produced by the model. */
78
+ arguments: string;
79
+ }
80
+ /** The result of a tool invocation, sent back to the model. */
81
+ export interface ToolResultBlock {
82
+ type: 'tool-result';
83
+ toolCallId: ToolCallId;
84
+ content: ContentBlock[];
85
+ isError?: boolean;
86
+ }
87
+ /**
88
+ * Merge-extensible content blocks keyed by `type`. New core blocks must land
89
+ * with adapter, UI, and compaction support.
90
+ */
91
+ export interface ContentBlockMap {
92
+ 'text': TextBlock;
93
+ 'reasoning': ReasoningBlock;
94
+ 'image': ImageBlock;
95
+ 'file': FileBlock;
96
+ 'tool-call': ToolCallBlock;
97
+ 'tool-result': ToolResultBlock;
98
+ }
99
+ /** The block `type` tag vocabulary; widens as plugins add entries to {@link ContentBlockMap}. */
100
+ export type ContentBlockType = keyof ContentBlockMap;
101
+ /** Any known content block, derived from {@link ContentBlockMap}; switch on `type` and fall through unknowns (merge-extensible). */
102
+ export type ContentBlock = ContentBlockMap[ContentBlockType];
103
+ /**
104
+ * Why a model response stopped.
105
+ * Merge-extensible so adapters can surface provider-specific reasons.
106
+ */
107
+ export interface FinishReasonMap {
108
+ 'stop': {
109
+ kind: 'stop';
110
+ };
111
+ 'tool-calls': {
112
+ kind: 'tool-calls';
113
+ };
114
+ 'max-tokens': {
115
+ kind: 'max-tokens';
116
+ };
117
+ 'aborted': {
118
+ kind: 'aborted';
119
+ failure: LlmFailure;
120
+ };
121
+ 'error': {
122
+ kind: 'error';
123
+ failure: LlmFailure;
124
+ };
125
+ }
126
+ /** Any known finish reason, derived from {@link FinishReasonMap}; switch on `kind` and fall through unknowns (merge-extensible). */
127
+ export type FinishReason = FinishReasonMap[keyof FinishReasonMap];
128
+ /**
129
+ * Token accounting for one model call (cache fields are optional).
130
+ *
131
+ * Counts are DISJOINT: `inputTokens` is uncached input only; cached input is
132
+ * reported separately as `cacheReadTokens`/`cacheWriteTokens` (billed input =
133
+ * sum of the three). Adapters whose providers fold cache hits into a total
134
+ * prompt count (a chat-completions `prompt_tokens`) subtract them out.
135
+ */
136
+ export interface TokenUsage {
137
+ inputTokens: number;
138
+ outputTokens: number;
139
+ /**
140
+ * Exact full-call total including aggregate prompt and output tokens.
141
+ *
142
+ * Adapters preserve a provider total or derive it from authoritative
143
+ * aggregate prompt/output counters; they omit it when unavailable or
144
+ * inconsistent.
145
+ */
146
+ totalTokens?: number;
147
+ cacheReadTokens?: number;
148
+ cacheWriteTokens?: number;
149
+ reasoningTokens?: number;
150
+ }
151
+ /**
152
+ * Request price of one ordered image occurrence under one exact model route's
153
+ * request projection. Every occurrence resolves to the pair the wire actually
154
+ * carries: provider visual tokens for a retained image, plus the model-visible
155
+ * text sent with or instead of it (request-preview handle, offload placeholder,
156
+ * or text-only substitution). The caller prices `text` with its own text
157
+ * estimator so provider pricing never fixes a text tokenization.
158
+ */
159
+ export interface LlmImageRequestPrice {
160
+ /** Provider visual tokens for the retained request image; 0 when only text represents this occurrence. */
161
+ visualTokens: number;
162
+ /** Model-visible text sent for this occurrence, to be priced by the caller's text estimator. */
163
+ text: string;
164
+ }
165
+ /**
166
+ * Provider-side request-image pricing for one exact model route. Implemented
167
+ * by adapters whose provider charges visual tokens; consumers (the token
168
+ * meter) resolve it synchronously per measurement, so implementations must not
169
+ * perform I/O.
170
+ */
171
+ export interface LlmImageRequestPricing {
172
+ /**
173
+ * Price every image occurrence of one request projection.
174
+ * @param images - durable image references in request order, one entry per occurrence.
175
+ * @returns one price per occurrence, aligned by index with `images`.
176
+ */
177
+ priceImages(images: readonly ImageAttachmentRef[]): readonly LlmImageRequestPrice[];
178
+ }
179
+ /** Display metadata for one registered provider route. */
180
+ export interface LlmProviderInfo {
181
+ /** Provider route key used by {@link GenerateOptions.provider}. */
182
+ id: string;
183
+ /** Human-readable provider name for selectors and diagnostics. */
184
+ name: string;
185
+ }
186
+ /** Merge-extensible provider model modality vocabulary. */
187
+ export interface ModelModalityMap {
188
+ text: 'text';
189
+ image: 'image';
190
+ }
191
+ /** Any declared provider model modality. */
192
+ export type ModelModality = ModelModalityMap[keyof ModelModalityMap];
193
+ /**
194
+ * One provider route an adapter plugin can activate through configuration,
195
+ * whether or not the route is currently registered. Configuration surfaces
196
+ * merge this directory with `listProviders()` to offer every configurable
197
+ * provider alongside its live/dormant state.
198
+ */
199
+ export interface LlmConfigurableProvider {
200
+ /** Provider route key this entry activates when configured. */
201
+ provider: string;
202
+ /** Human-readable provider name for configuration surfaces. */
203
+ displayName: string;
204
+ /** User-settings namespace whose section configures this provider. */
205
+ settingsNs: string;
206
+ /**
207
+ * Path from that namespace's section root to this provider's profile
208
+ * object; empty when the whole section is the profile.
209
+ */
210
+ settingsPath: readonly string[];
211
+ /**
212
+ * Whether the owning adapter knows this route only because configuration
213
+ * declared it — a gateway or self-hosted server it ships nothing about.
214
+ * Absent means the adapter draws no such distinction; false means it does
215
+ * and this route is one of its own. Only the adapter can answer: a stored
216
+ * profile is how a user-added route AND a corrected shipped one both look
217
+ * from outside.
218
+ */
219
+ declared?: boolean;
220
+ }
221
+ /**
222
+ * One interrogation of a provider endpoint that configuration has not stored
223
+ * yet. Configuration surfaces send the draft a user is still editing, so the
224
+ * request carries the endpoint and credential directly instead of naming a
225
+ * route: a provider being added has no route to name.
226
+ */
227
+ export interface LlmModelDiscoveryRequest {
228
+ /**
229
+ * Route the draft is editing, when it edits an existing one. A route whose
230
+ * adapter already knows its models answers from that knowledge instead of
231
+ * asking the endpoint — the adapter's own registry is the better answer, and
232
+ * it costs no network call.
233
+ */
234
+ provider?: string;
235
+ /**
236
+ * Endpoint to interrogate. Optional because a route the adapter already
237
+ * describes needs none; a route it does not must supply one.
238
+ */
239
+ baseURL?: string;
240
+ /** Wire protocol the endpoint speaks, when the draft names one. */
241
+ api?: string;
242
+ /** Credential for this interrogation alone; the harness never stores it. */
243
+ apiKey?: string;
244
+ }
245
+ /** Provider-side discovery request with operation-local cancellation attached. */
246
+ export interface LlmModelDiscoveryOperation extends LlmModelDiscoveryRequest {
247
+ /** Caller cancellation; implementations must settle promptly after it aborts. */
248
+ signal?: AbortSignal;
249
+ }
250
+ declare module '@xlaunch/typert-protocol' {
251
+ interface RemoteErrorDetailsMap {
252
+ /** A draft provider interrogation refused or failed. */
253
+ 'llm/model-discovery-rejected': {
254
+ readonly settingsNs: string;
255
+ readonly baseURL?: string;
256
+ };
257
+ }
258
+ }
259
+ /**
260
+ * One model an endpoint reports about itself. Every field but the id is
261
+ * optional because most provider listings disclose an id and nothing else;
262
+ * a surface adopting one of these still owes the capacities its adapter needs.
263
+ */
264
+ export interface LlmDiscoveredModel {
265
+ /** Model id the endpoint accepts. */
266
+ id: string;
267
+ /** Human-readable name when the endpoint supplies one. */
268
+ name?: string;
269
+ /** Maximum combined request and response context, when disclosed. */
270
+ contextWindow?: number;
271
+ /** Maximum output tokens, when disclosed. */
272
+ maxTokens?: number;
273
+ }
274
+ /** One adapter-discovered model; catalog membership is advisory, not request validation. */
275
+ export interface LlmModelInfo {
276
+ /** Provider route that owns this model entry. */
277
+ provider: string;
278
+ /** Model id passed to {@link GenerateOptions.model}. */
279
+ id: string;
280
+ /** Human-readable model name for selectors. */
281
+ name: string;
282
+ /** Optional user-facing distinction from otherwise similar models. */
283
+ description?: string;
284
+ /** Accepted request modalities; absent means unknown, while an explicit omission is negative capability. */
285
+ inputModalities?: readonly ModelModality[];
286
+ }
287
+ /** Provider-owned context capacity for one exact provider/model route. */
288
+ export interface LlmModelContext {
289
+ /** Maximum combined request and response context in tokens. */
290
+ contextWindow: number;
291
+ }
292
+ /** Display metadata for one adapter-owned reasoning effort. */
293
+ export interface LlmReasoningEffortInfo {
294
+ /** Opaque stable value accepted by {@link GenerateOptions.reasoningEffort}. */
295
+ id: ReasoningEffortId;
296
+ /** Human-readable effort name for selectors and diagnostics. */
297
+ name: string;
298
+ /** Optional user-facing distinction from otherwise similar efforts. */
299
+ description?: string;
300
+ }
301
+ /** Selectable reasoning efforts for one exact provider/model route. */
302
+ export interface LlmModelReasoningInfo {
303
+ /** Supported efforts in adapter-preferred display order. */
304
+ efforts: readonly LlmReasoningEffortInfo[];
305
+ /**
306
+ * Adapter-configured default materialized into requests when callers omit
307
+ * an effort. Absence preserves the provider's own default.
308
+ */
309
+ defaultEffort?: ReasoningEffortId;
310
+ }
311
+ /** Exact-route model metadata resolved by its owning adapter. */
312
+ export interface LlmResolvedModelInfo extends LlmModelInfo {
313
+ /** Provider-owned context capacity when known. */
314
+ context?: LlmModelContext;
315
+ /** Adapter-configured per-request output cap materialized when callers omit one. */
316
+ defaultMaxTokens?: number;
317
+ /** Adapter-owned selectable reasoning levels when exposed. */
318
+ reasoning?: LlmModelReasoningInfo;
319
+ }
320
+ /**
321
+ * Adapter-private lossless-JSON state for replaying a successful response,
322
+ * carried by a terminal `finish` chunk and stored on the assembled assistant
323
+ * message's model source. Both halves stay opaque to the harness; only the
324
+ * split is shared vocabulary, so assembly can keep stored metadata aligned
325
+ * with stored content without reading either half.
326
+ */
327
+ export interface ReplayEnvelope {
328
+ /** Response-level adapter-private metadata (ids, native stop reason). */
329
+ response: unknown;
330
+ /**
331
+ * Per-block adapter-private metadata, one entry per emitted block in
332
+ * first-seen stream order. When assembly drops a block it drops the entry at
333
+ * the same position; entries whose length does not match the emitted block
334
+ * count discard the whole envelope. An adapter whose metadata is independent
335
+ * of block structure omits this field and the envelope passes through
336
+ * assembly unchanged.
337
+ */
338
+ blocks?: readonly unknown[];
339
+ }
340
+ /**
341
+ * Raw streaming protocol emitted by adapters.
342
+ * Block indexes correlate interleaved deltas, and `block-end` carries the
343
+ * assembled block. Adapters emit usage before the terminal finish and nothing
344
+ * afterward; tool arguments remain raw JSON strings. An adapter implementation
345
+ * may throw, but `LlmRuntime.stream()` normalizes that failure to a terminal
346
+ * `error` or `aborted` finish before exposing it to consumers.
347
+ */
348
+ export type StreamChunk = {
349
+ type: 'block-start';
350
+ index: number;
351
+ blockType: ContentBlockType;
352
+ } | {
353
+ type: 'text-delta';
354
+ index: number;
355
+ text: string;
356
+ } | {
357
+ type: 'reasoning-delta';
358
+ index: number;
359
+ text: string;
360
+ } | {
361
+ type: 'tool-call-delta';
362
+ index: number;
363
+ id: ToolCallId;
364
+ name?: string;
365
+ argumentsDelta: string;
366
+ } | {
367
+ type: 'block-end';
368
+ index: number;
369
+ block: ContentBlock;
370
+ } | {
371
+ type: 'usage';
372
+ usage: TokenUsage;
373
+ } | {
374
+ type: 'finish';
375
+ reason: FinishReason;
376
+ /** Replay metadata for a successful response; see {@link ReplayEnvelope}. */
377
+ replayState?: ReplayEnvelope;
378
+ };
379
+ /**
380
+ * JSON-schema description of a tool, as sent to the model.
381
+ *
382
+ * Declared here (not in xlaunch-tools) because it is part of {@link GenerateOptions};
383
+ * xlaunch-tools' ToolDefinition and xlaunch-system-prompt's PromptAssembly both import
384
+ * it from this package.
385
+ */
386
+ export interface ToolSchema {
387
+ name: string;
388
+ description: string;
389
+ /** JSON Schema object for the arguments. */
390
+ parameters: Record<string, unknown>;
391
+ }
392
+ /** A single model request, fully assembled. */
393
+ export interface GenerateOptions {
394
+ /** Registered provider route selecting the adapter instance. */
395
+ provider: string;
396
+ model: string;
397
+ /** Adapter-owned reasoning effort selected for this exact model. */
398
+ reasoningEffort?: ReasoningEffortId;
399
+ /**
400
+ * Ordered conversation messages, exactly as the provider sees them (after
401
+ * the `system` slot). A loop-built request assembles them as
402
+ * the derived history (xlaunch-agent-loop); a hand-built one-shot passes any list.
403
+ */
404
+ messages: Message[];
405
+ /** System prompt text (adapters map to the provider's system slot). */
406
+ system?: string;
407
+ /** Tool schemas (adapters map to the provider's `tools` field). */
408
+ tools?: ToolSchema[];
409
+ temperature?: number;
410
+ maxTokens?: number;
411
+ /**
412
+ * Stop sequences: generation halts as soon as the model produces any one of
413
+ * these strings (adapters map to the provider's stop field, e.g. OpenAI
414
+ * `stop`). The stop string itself is not included in the output.
415
+ */
416
+ stop?: string[];
417
+ signal?: AbortSignal;
418
+ /**
419
+ * Session identity stamped by the loop for request routing. Replay uses it
420
+ * to separate cursors; adapters may map it to model-hidden transport metadata.
421
+ */
422
+ sessionId?: Branded<'SessionId'>;
423
+ /**
424
+ * Provider-neutral classification for an auxiliary model call. Adapters may
425
+ * map the purpose to model-hidden transport metadata or purpose-specific
426
+ * generation policy. Ordinary conversation requests leave it unset.
427
+ */
428
+ purpose?: 'compaction' | 'session-title';
429
+ }
430
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Canonical provider-neutral message and streaming vocabulary for the loop,
3
+ * session log, and plugins. Adapters alone translate provider wire messages;
4
+ * mapped interfaces make the content, source, and finish unions extensible.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=types.js.map
package/package.json ADDED
@@ -0,0 +1,81 @@
1
+ {
2
+ "name": "@xlaunch/llm",
3
+ "description": "Provider-neutral LLM service interface for the Xlaunch",
4
+ "version": "0.2.0-beta.1",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/Northlatch-Labs-LLC/xlaunch-agent.git",
11
+ "directory": "packages/llm/llm"
12
+ },
13
+ "type": "module",
14
+ "main": "lib/index.js",
15
+ "types": "lib/types/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./lib/types/index.d.ts",
19
+ "default": "./lib/index.js"
20
+ },
21
+ "./invariant": {
22
+ "types": "./lib/types/invariant.d.ts",
23
+ "default": "./lib/invariant.js"
24
+ },
25
+ "./types": {
26
+ "types": "./lib/types/types.d.ts",
27
+ "default": "./lib/types/types.js"
28
+ },
29
+ "./brand": {
30
+ "types": "./lib/types/brand.d.ts",
31
+ "default": "./lib/types/brand.js"
32
+ },
33
+ "./message": {
34
+ "types": "./lib/types/message.d.ts",
35
+ "default": "./lib/types/message.js"
36
+ },
37
+ "./assistant-stream": {
38
+ "types": "./lib/types/assistant-stream.d.ts",
39
+ "default": "./lib/types/assistant-stream.js"
40
+ },
41
+ "./typert": {
42
+ "types": "./lib/typert.host.d.ts",
43
+ "default": "./lib/typert.host.js"
44
+ },
45
+ "./remote": {
46
+ "types": "./lib/typert.remote-client.d.ts",
47
+ "default": "./lib/typert.remote-client.js"
48
+ },
49
+ "./src/*": "./src/*",
50
+ "./package.json": "./package.json"
51
+ },
52
+ "files": [
53
+ "lib/index.js",
54
+ "lib/invariant.js",
55
+ "lib/types/**/*.js",
56
+ "lib/types/**/*.d.ts",
57
+ "lib/typert.host.js",
58
+ "lib/typert.host.d.ts",
59
+ "lib/typert.remote-client.js",
60
+ "lib/typert.remote-client.d.ts"
61
+ ],
62
+ "license": "MIT",
63
+ "author": "Northlatch Labs LLC",
64
+ "peerDependencies": {
65
+ "@xlaunch/cordis": "^4.0.2"
66
+ },
67
+ "dependencies": {
68
+ "zod": "^4.4.3",
69
+ "@xlaunch/timeout": "^0.2.0-beta.1",
70
+ "@xlaunch/util-crypto": "^0.2.0-beta.1",
71
+ "@xlaunch/brand": "^0.2.0-beta.1",
72
+ "@xlaunch/schemastery": "^3.18.2",
73
+ "@xlaunch/util-values": "^0.2.0-beta.1",
74
+ "@xlaunch/typert-protocol": "^0.2.0-beta.1"
75
+ },
76
+ "devDependencies": {
77
+ "@xlaunch/attachment": "^0.2.0-beta.1",
78
+ "@xlaunch/invariants": "^0.2.0-beta.1",
79
+ "@xlaunch/cordis": "^4.0.2"
80
+ }
81
+ }