@cleocode/contracts 2026.5.65 → 2026.5.67

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 (40) hide show
  1. package/dist/index.d.ts +6 -0
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js.map +1 -1
  4. package/dist/llm/failover-reason.d.ts +76 -0
  5. package/dist/llm/failover-reason.d.ts.map +1 -0
  6. package/dist/llm/failover-reason.js +2 -0
  7. package/dist/llm/failover-reason.js.map +1 -0
  8. package/dist/llm/interfaces.d.ts +476 -0
  9. package/dist/llm/interfaces.d.ts.map +1 -0
  10. package/dist/llm/interfaces.js +24 -0
  11. package/dist/llm/interfaces.js.map +1 -0
  12. package/dist/llm/normalized-response.d.ts +304 -0
  13. package/dist/llm/normalized-response.d.ts.map +1 -0
  14. package/dist/llm/normalized-response.js +19 -0
  15. package/dist/llm/normalized-response.js.map +1 -0
  16. package/dist/llm/provider-id.d.ts +47 -0
  17. package/dist/llm/provider-id.d.ts.map +1 -0
  18. package/dist/llm/provider-id.js +13 -0
  19. package/dist/llm/provider-id.js.map +1 -0
  20. package/dist/llm/provider-profile.d.ts +166 -0
  21. package/dist/llm/provider-profile.d.ts.map +1 -0
  22. package/dist/llm/provider-profile.js +13 -0
  23. package/dist/llm/provider-profile.js.map +1 -0
  24. package/dist/llm/resolved-credential.d.ts +61 -0
  25. package/dist/llm/resolved-credential.d.ts.map +1 -0
  26. package/dist/llm/resolved-credential.js +14 -0
  27. package/dist/llm/resolved-credential.js.map +1 -0
  28. package/dist/operations/llm.d.ts +14 -2
  29. package/dist/operations/llm.d.ts.map +1 -1
  30. package/dist/operations/llm.js +4 -0
  31. package/dist/operations/llm.js.map +1 -1
  32. package/package.json +10 -2
  33. package/src/index.ts +43 -0
  34. package/src/llm/failover-reason.ts +86 -0
  35. package/src/llm/interfaces.ts +538 -0
  36. package/src/llm/normalized-response.ts +313 -0
  37. package/src/llm/provider-id.ts +63 -0
  38. package/src/llm/provider-profile.ts +191 -0
  39. package/src/llm/resolved-credential.ts +62 -0
  40. package/src/operations/llm.ts +20 -2
@@ -0,0 +1,304 @@
1
+ /**
2
+ * Normalized provider response types for the CLEO LLM transport layer.
3
+ *
4
+ * Ported from Hermes `agent/transports/types.py` (Python dataclasses →
5
+ * TypeScript interfaces, snake_case → camelCase). These types define the
6
+ * canonical shape that all provider transports normalize responses to. The
7
+ * shared surface is intentionally minimal — only fields that every downstream
8
+ * consumer reads are top-level. Protocol-specific state goes in `providerData`
9
+ * dicts so that protocol-aware code paths can access it without polluting the
10
+ * shared type.
11
+ *
12
+ * @module llm/normalized-response
13
+ * @task T9263
14
+ * @task T9282 (W0c — Phase 4 multimodal + stream extensions)
15
+ * @epic T-LLM-CRED-CENTRALIZATION
16
+ * @see ADR-072 §LlmTransport — pure wire level
17
+ */
18
+ import type { ModelTransport } from '../operations/llm.js';
19
+ import type { NormalizedDelta, TransportContext } from './interfaces.js';
20
+ import type { ApiMode } from './provider-id.js';
21
+ /**
22
+ * Token usage reported by the provider for a single API call.
23
+ *
24
+ * `cachedTokens` is only populated when the provider supports prompt-cache
25
+ * read accounting (Anthropic extended caching, Gemini cached content).
26
+ */
27
+ export interface NormalizedUsage {
28
+ /** Tokens consumed by the prompt. */
29
+ inputTokens: number;
30
+ /** Tokens generated by the model. */
31
+ outputTokens: number;
32
+ /** Tokens served from prompt cache (if provider supports caching). */
33
+ cachedTokens?: number;
34
+ }
35
+ /**
36
+ * A single normalized tool call emitted by the model.
37
+ *
38
+ * `id` is the protocol-canonical identifier used when constructing tool result
39
+ * messages. May be `null` when the provider omits it (rare in practice but
40
+ * possible with some adapters).
41
+ *
42
+ * `providerData` carries per-tool-call protocol metadata that only
43
+ * protocol-aware code reads. Examples:
44
+ * - Codex: `{ call_id: "call_XXX", response_item_id: "fc_XXX" }`
45
+ * - Gemini: `{ extra_content: { thought_signature: "..." } }`
46
+ */
47
+ export interface NormalizedToolCall {
48
+ /** Provider-assigned tool-call id (may be null if provider does not surface one). */
49
+ id: string | null;
50
+ /** Tool name as declared in the request. */
51
+ name: string;
52
+ /** Arguments as a JSON string (provider-agnostic). */
53
+ arguments: string;
54
+ /** Provider-specific extras (raw shape, do not depend on). */
55
+ providerData?: Record<string, unknown>;
56
+ }
57
+ /**
58
+ * Normalized API response from any LLM provider.
59
+ *
60
+ * Shared fields are truly cross-provider — every caller can rely on them
61
+ * without branching on transport. Protocol-specific state goes in
62
+ * `providerData` so that only protocol-aware code paths read it.
63
+ *
64
+ * `raw` is the unmodified SDK response object. Consumers MUST narrow it with
65
+ * a type guard before accessing fields. NEVER log `raw` without scrubbing
66
+ * auth headers.
67
+ */
68
+ export interface NormalizedResponse {
69
+ /** Response id from the provider (or a synthesized id if absent). */
70
+ id: string;
71
+ /** Model identifier as reported by the provider. */
72
+ model: string;
73
+ /** Plain text content (null when the model returned only tool calls). */
74
+ content: string | null;
75
+ /** Tool calls, or null when none. */
76
+ toolCalls: NormalizedToolCall[] | null;
77
+ /**
78
+ * Provider-reported stop reason.
79
+ * Common values: `'end_turn'`, `'tool_use'`, `'stop'`, `'max_tokens'`,
80
+ * `'stop_sequence'`, `'tool_calls'`, `'length'`.
81
+ */
82
+ stopReason: string;
83
+ /** Token usage for this call. */
84
+ usage: NormalizedUsage;
85
+ /**
86
+ * Optional model-internal reasoning trace.
87
+ * Populated for Anthropic extended-thinking and OpenAI o1-series models.
88
+ */
89
+ reasoning?: string | null;
90
+ /** Provider-specific response-level extras (raw shape, do not depend on). */
91
+ providerData?: Record<string, unknown>;
92
+ /**
93
+ * Raw provider response — DO NOT log this without scrubbing auth headers.
94
+ *
95
+ * Typed as `unknown` because the concrete SDK response shapes
96
+ * (Anthropic.Message, OpenAI.ChatCompletion, …) are not imported from
97
+ * contracts. Consumers MUST narrow with a type guard before accessing fields.
98
+ */
99
+ raw: unknown;
100
+ }
101
+ /**
102
+ * An image content block for multimodal messages.
103
+ *
104
+ * `source.type` determines how the image data is provided:
105
+ * - `'base64'` — raw image bytes encoded as base64, with `mediaType` identifying
106
+ * the MIME type (e.g. `'image/png'`, `'image/jpeg'`).
107
+ * - `'url'` — a publicly accessible URL; `data` is the URL string and `mediaType`
108
+ * is still populated (sniffed by {@link image-routing.ts} when not supplied by
109
+ * the caller).
110
+ *
111
+ * @see ADR-072 §LlmTransport — pure wire level (W4d image routing)
112
+ */
113
+ export interface TransportImageBlock {
114
+ /** Discriminant — always `'image'`. */
115
+ readonly type: 'image';
116
+ readonly source: {
117
+ /** How the image data is provided. */
118
+ readonly type: 'base64' | 'url';
119
+ /**
120
+ * Base64-encoded image bytes (when `type === 'base64'`) or a URL string
121
+ * (when `type === 'url'`).
122
+ */
123
+ readonly data: string;
124
+ /** MIME type, e.g. `'image/png'`, `'image/jpeg'`, `'image/webp'`. */
125
+ readonly mediaType: string;
126
+ };
127
+ }
128
+ /**
129
+ * A text content block for multimodal messages.
130
+ */
131
+ export interface TransportTextBlock {
132
+ /** Discriminant — always `'text'`. */
133
+ readonly type: 'text';
134
+ /** Plain text string. */
135
+ readonly text: string;
136
+ }
137
+ /**
138
+ * A single message in a provider-neutral conversation turn.
139
+ *
140
+ * `toolUseId` is required when `role` is `'tool'` — it identifies which
141
+ * tool call this result resolves, matching {@link NormalizedToolCall.id}.
142
+ *
143
+ * `content` supports both the legacy plain-string form and a multimodal block
144
+ * array. When `content` is a string, the transport treats it as a single text
145
+ * block. When it is an array, each element is either a {@link TransportTextBlock}
146
+ * or a {@link TransportImageBlock} — enabling image routing (W4d) without
147
+ * breaking existing transport consumers that only read the string form.
148
+ */
149
+ export interface TransportMessage {
150
+ /** Conversation turn role. */
151
+ role: 'user' | 'assistant' | 'tool';
152
+ /**
153
+ * Message content.
154
+ *
155
+ * - Plain `string` — backwards-compatible single-text-block form used by
156
+ * all existing transports. Transports that do not support images receive
157
+ * this form only.
158
+ * - `ReadonlyArray<TransportTextBlock | TransportImageBlock>` — multimodal
159
+ * block array enabling image routing (ADR-072 W4d). Transports that do not
160
+ * support images MUST stringify text blocks and drop image blocks (or throw
161
+ * if `imageMode` on the request is `'native'` — see {@link TransportRequest}).
162
+ */
163
+ readonly content: string | ReadonlyArray<TransportTextBlock | TransportImageBlock>;
164
+ /** Tool-result messages: id of the call this resolves. */
165
+ toolUseId?: string;
166
+ }
167
+ /**
168
+ * A tool definition passed to the provider.
169
+ *
170
+ * `inputSchema` is a JSON Schema object describing the tool's input parameters.
171
+ * The transport layer passes it through verbatim after any provider-specific
172
+ * adaptation (e.g. Anthropic wraps it in `{ type: "object", ... }`).
173
+ */
174
+ export interface TransportTool {
175
+ /** Tool name as it will appear in {@link NormalizedToolCall.name}. */
176
+ name: string;
177
+ /** Human-readable description for the model. */
178
+ description: string;
179
+ /** JSON Schema for input parameters. */
180
+ inputSchema: Record<string, unknown>;
181
+ }
182
+ /**
183
+ * Request parameters passed to {@link LlmTransport.complete} and
184
+ * {@link LlmTransport.stream}.
185
+ *
186
+ * `temperature` is normalized to the 0.0–1.0 range; each transport clamps it
187
+ * to the provider's supported range before sending.
188
+ *
189
+ * `signal` may be used to abort in-flight requests (passed through to the
190
+ * underlying fetch / SDK call where supported).
191
+ *
192
+ * @see ADR-072 §LlmTransport — pure wire level
193
+ */
194
+ export interface TransportRequest {
195
+ /** Model identifier — provider-specific (e.g. `'claude-sonnet-4-6'`). */
196
+ model: string;
197
+ /** Conversation messages in provider-neutral form. */
198
+ messages: TransportMessage[];
199
+ /** Maximum tokens to generate (NOT input budget). */
200
+ maxTokens: number;
201
+ /** Optional system prompt (Anthropic top-level `system`) or system message (OpenAI). */
202
+ system?: string;
203
+ /** Optional tools the model may call. */
204
+ tools?: TransportTool[];
205
+ /** Sampling temperature in 0.0–1.0 range; provider clamps to its own range. */
206
+ temperature?: number;
207
+ /** AbortSignal for request cancellation. */
208
+ signal?: AbortSignal;
209
+ /**
210
+ * Prompt-cache breakpoint injection strategy.
211
+ *
212
+ * - `'system_and_3'` — inject cache breakpoints after the system prompt and
213
+ * after the last 3 user messages (Anthropic extended-caching strategy).
214
+ * - `'prefix_and_2'` — inject at the shared prefix boundary and after the 2
215
+ * most-recent turns (optimised for Gemini cached content).
216
+ * - `null` — no cache injection (default when not set).
217
+ *
218
+ * Transports apply the selected strategy before constructing the SDK request.
219
+ * Unsupported strategies on a given transport are silently ignored.
220
+ *
221
+ * @see ADR-072 §LlmTransport — pure wire level
222
+ */
223
+ readonly cacheStrategy?: 'system_and_3' | 'prefix_and_2' | null;
224
+ /**
225
+ * Image handling mode for multimodal content blocks in {@link TransportMessage.content}.
226
+ *
227
+ * - `'native'` — send image blocks as-is to the provider's multimodal API.
228
+ * The transport MUST throw if the provider does not support native images.
229
+ * - `'text'` — strip all image blocks; only text blocks are sent. Useful for
230
+ * text-only providers or when images are redundant.
231
+ * - `'auto'` — the transport decides based on provider capability (default).
232
+ * Falls back to `'text'` for providers that do not support native images.
233
+ *
234
+ * Used by the image-routing layer (W4d) to select the per-turn input mode.
235
+ *
236
+ * @see ADR-072 §LlmTransport — pure wire level
237
+ */
238
+ readonly imageMode?: 'native' | 'text' | 'auto';
239
+ }
240
+ /**
241
+ * Provider transport contract.
242
+ *
243
+ * Each concrete transport (Anthropic, OpenAI, Gemini) implements this
244
+ * interface and maps provider-specific API shapes to/from
245
+ * {@link NormalizedResponse}. Role-resolver and executor code works
246
+ * exclusively against this interface so providers are swappable.
247
+ *
248
+ * As of Phase 4 (ADR-072) the interface gains two additional members:
249
+ * - {@link apiMode} — the wire protocol spoken by this transport.
250
+ * - {@link stream} — streaming completion returning {@link NormalizedDelta} chunks.
251
+ *
252
+ * Existing transport implementations MUST add stub implementations of both to
253
+ * maintain compile parity (W0c). Wave 1 migrations replace stubs with real impls.
254
+ *
255
+ * @see ADR-072 §LlmTransport — pure wire level
256
+ */
257
+ export interface LlmTransport {
258
+ /**
259
+ * Provider identifier — matches the `ModelTransport` union so role-resolver
260
+ * can select the correct transport at runtime.
261
+ */
262
+ readonly provider: ModelTransport;
263
+ /**
264
+ * Wire protocol this transport speaks. Used by the session and executor layers
265
+ * to select correct transports for providers that support multiple protocols.
266
+ *
267
+ * @see ADR-072 §Type lock-in — `ApiMode` closed 4-value union
268
+ */
269
+ readonly apiMode: ApiMode;
270
+ /**
271
+ * Execute a single completion call and return a normalized response.
272
+ *
273
+ * Implementations MUST:
274
+ * - Never return raw credentials in the response envelope.
275
+ * - Preserve the full provider response in {@link NormalizedResponse.raw}.
276
+ * - Map provider-specific stop reasons to the canonical set where possible.
277
+ *
278
+ * @param request - Provider-neutral request parameters.
279
+ * @param ctx - Contextual metadata (request ID, abort signal, feature flags).
280
+ * @returns A promise that resolves to a {@link NormalizedResponse}.
281
+ */
282
+ complete(request: TransportRequest, ctx?: TransportContext): Promise<NormalizedResponse>;
283
+ /**
284
+ * Stream a completion. Each {@link NormalizedDelta} carries incremental text
285
+ * or reasoning content.
286
+ *
287
+ * Implementors MUST run streaming deltas through `StreamingThinkScrubber`
288
+ * before yielding them — reasoning content goes to `delta.reasoning`;
289
+ * visible text goes to `delta.text`. The final delta has a non-null
290
+ * `stopReason` and carries full usage stats in `delta.usage`.
291
+ *
292
+ * W0c transports carry a stub that throws until Wave 1 migration lands:
293
+ * ```ts
294
+ * throw new Error('STUB: W1 migration will implement stream() for <provider>');
295
+ * ```
296
+ *
297
+ * @param request - Provider-neutral request parameters.
298
+ * @param ctx - Contextual metadata (request ID, abort signal, feature flags).
299
+ * @returns An async iterable of normalized delta chunks.
300
+ * @see ADR-072 §LlmTransport — pure wire level
301
+ */
302
+ stream(request: TransportRequest, ctx: TransportContext): AsyncIterable<NormalizedDelta>;
303
+ }
304
+ //# sourceMappingURL=normalized-response.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalized-response.d.ts","sourceRoot":"","sources":["../../src/llm/normalized-response.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Normalized provider response types for the CLEO LLM transport layer.
3
+ *
4
+ * Ported from Hermes `agent/transports/types.py` (Python dataclasses →
5
+ * TypeScript interfaces, snake_case → camelCase). These types define the
6
+ * canonical shape that all provider transports normalize responses to. The
7
+ * shared surface is intentionally minimal — only fields that every downstream
8
+ * consumer reads are top-level. Protocol-specific state goes in `providerData`
9
+ * dicts so that protocol-aware code paths can access it without polluting the
10
+ * shared type.
11
+ *
12
+ * @module llm/normalized-response
13
+ * @task T9263
14
+ * @task T9282 (W0c — Phase 4 multimodal + stream extensions)
15
+ * @epic T-LLM-CRED-CENTRALIZATION
16
+ * @see ADR-072 §LlmTransport — pure wire level
17
+ */
18
+ export {};
19
+ //# sourceMappingURL=normalized-response.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalized-response.js","sourceRoot":"","sources":["../../src/llm/normalized-response.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Provider identity and API protocol types for the unified LLM provider architecture.
3
+ *
4
+ * These types anchor the Phase 4 contract layer (ADR-072). All downstream code
5
+ * that references a provider by name or by wire-protocol uses these types.
6
+ *
7
+ * @module llm/provider-id
8
+ * @task T9281
9
+ * @epic T9261 T-LLM-CRED-CENTRALIZATION
10
+ * @see ADR-072 §Type lock-in
11
+ */
12
+ /**
13
+ * Canonical wire-level API protocol supported by a provider.
14
+ *
15
+ * Closed 4-value union. Providers that speak multiple protocols (e.g. OpenAI
16
+ * supports both chat_completions and codex_responses) declare separate
17
+ * ProviderProfiles, one per ApiMode.
18
+ *
19
+ * Adding a fifth value is a major breaking change — confirm in ADR-072 before doing so.
20
+ *
21
+ * @see ADR-072 §Type lock-in
22
+ */
23
+ export type ApiMode = 'chat_completions' | 'anthropic_messages' | 'codex_responses' | 'bedrock_converse';
24
+ /**
25
+ * Fixed set of builtin provider identifiers shipped with CLEO core.
26
+ *
27
+ * Plugin providers registered at runtime may use any non-empty string —
28
+ * see {@link ProviderId}.
29
+ *
30
+ * MIGRATION NOTE: The legacy `ModelTransport` ('anthropic'|'openai'|'gemini'|'moonshot')
31
+ * is re-typed as `Extract<ProviderId, BuiltinProviderId>` for one release cycle
32
+ * (deprecated, then removed).
33
+ */
34
+ export type BuiltinProviderId = 'anthropic' | 'openai' | 'gemini' | 'moonshot' | 'openrouter' | 'bedrock' | 'deepseek' | 'xai' | 'groq' | 'kimi-code';
35
+ /**
36
+ * Provider identity string.
37
+ *
38
+ * Builtin providers use the fixed literals in {@link BuiltinProviderId}.
39
+ * Plugin providers registered at runtime via `ProviderRegistry` may use any
40
+ * non-empty string. The open string union allows plugins without forcing
41
+ * exhaustive switch checks in transport code (match arms should include a
42
+ * default/unknown branch).
43
+ *
44
+ * @see ADR-072 §Type lock-in
45
+ */
46
+ export type ProviderId = BuiltinProviderId | (string & Record<never, never>);
47
+ //# sourceMappingURL=provider-id.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-id.d.ts","sourceRoot":"","sources":["../../src/llm/provider-id.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;;;;;;;;;GAUG;AACH,MAAM,MAAM,OAAO,GACf,kBAAkB,GAClB,oBAAoB,GACpB,iBAAiB,GACjB,kBAAkB,CAAC;AAEvB;;;;;;;;;GASG;AACH,MAAM,MAAM,iBAAiB,GACzB,WAAW,GACX,QAAQ,GACR,QAAQ,GACR,UAAU,GACV,YAAY,GACZ,SAAS,GACT,UAAU,GACV,KAAK,GACL,MAAM,GACN,WAAW,CAAC;AAEhB;;;;;;;;;;GAUG;AACH,MAAM,MAAM,UAAU,GAAG,iBAAiB,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Provider identity and API protocol types for the unified LLM provider architecture.
3
+ *
4
+ * These types anchor the Phase 4 contract layer (ADR-072). All downstream code
5
+ * that references a provider by name or by wire-protocol uses these types.
6
+ *
7
+ * @module llm/provider-id
8
+ * @task T9281
9
+ * @epic T9261 T-LLM-CRED-CENTRALIZATION
10
+ * @see ADR-072 §Type lock-in
11
+ */
12
+ export {};
13
+ //# sourceMappingURL=provider-id.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-id.js","sourceRoot":"","sources":["../../src/llm/provider-id.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
@@ -0,0 +1,166 @@
1
+ /**
2
+ * ProviderProfile interface and plugin contracts for the CLEO provider registry.
3
+ *
4
+ * Ported idiomatically from the Hermes provider registry (Python dataclass +
5
+ * importlib pattern → TypeScript interface + dynamic ESM import). This is the
6
+ * canonical type lock for Phase 3 of T-LLM-CRED-CENTRALIZATION — all
7
+ * subsequent Phase 3 tasks depend on this interface shape.
8
+ *
9
+ * @task T9262
10
+ * @epic T9261 (T-LLM-CRED-CENTRALIZATION Phase 3)
11
+ */
12
+ import type { ModelTransport, StoredAuthTypeWire } from '../operations/llm.js';
13
+ import type { TransportMessage, TransportTool } from './normalized-response.js';
14
+ /**
15
+ * Describes a single LLM provider — its auth capabilities, base URL,
16
+ * default model, and optional live model-discovery hook.
17
+ *
18
+ * Builtin providers (anthropic, openai, gemini, moonshot) ship with the
19
+ * registry. User plugins under `${CLEO_HOME}/plugins/model-providers/` may
20
+ * register additional profiles or override builtins (last-writer-wins).
21
+ */
22
+ export interface ProviderProfile {
23
+ /**
24
+ * Canonical provider name. For builtin providers this MUST match a
25
+ * {@link ModelTransport} so the credential resolver can wire the two
26
+ * systems together. User plugins may use any unique string.
27
+ */
28
+ name: ModelTransport | string;
29
+ /** Human-readable display name shown in pickers and diagnostic output. */
30
+ displayName: string;
31
+ /** Authentication schemes this provider supports. */
32
+ authTypes: ReadonlyArray<StoredAuthTypeWire>;
33
+ /**
34
+ * Base URL for the provider's API — no trailing slash.
35
+ *
36
+ * @example 'https://api.anthropic.com'
37
+ */
38
+ baseUrl: string;
39
+ /**
40
+ * Recommended default model identifier for this provider.
41
+ *
42
+ * @example 'claude-haiku-X-Y' (use the latest haiku from @cleocode/core/llm)
43
+ */
44
+ defaultModel: string;
45
+ /**
46
+ * Alternate names that resolve to this profile. Resolution is
47
+ * case-insensitive. Alias conflicts with another profile's primary name
48
+ * cause a `TypeError` at registration time.
49
+ */
50
+ aliases?: ReadonlyArray<string>;
51
+ /**
52
+ * HTTP headers sent with every request to this provider.
53
+ * Merged into the SDK client's `defaultHeaders`.
54
+ *
55
+ * @example { 'anthropic-version': '2023-06-01' }
56
+ */
57
+ defaultHeaders?: Readonly<Record<string, string>>;
58
+ /**
59
+ * Environment variable names that supply credentials for this provider.
60
+ * Sourced from the `env` field in the models.dev catalog when generated,
61
+ * or declared by hand-written builtins and plugins. Resolver chains may
62
+ * check these env vars for an API key before falling back to the
63
+ * credentials store.
64
+ *
65
+ * @example ['ANTHROPIC_API_KEY']
66
+ */
67
+ envVars?: ReadonlyArray<string>;
68
+ /**
69
+ * Optional live model-discovery hook. When present, the registry may
70
+ * call this to enumerate available model identifiers. Returns `null`
71
+ * when the provider does not support live model listing or when the
72
+ * fetch fails — callers MUST fall back to static model lists in that
73
+ * case.
74
+ *
75
+ * @param apiKey - The resolved API key (or OAuth bearer token).
76
+ * @param signal - Optional abort signal for request cancellation.
77
+ */
78
+ fetchModels?: (apiKey: string, signal?: AbortSignal) => Promise<ReadonlyArray<string> | null>;
79
+ /**
80
+ * Hook: transform messages before they are passed to the SDK.
81
+ *
82
+ * Default behavior (when `undefined`): identity — messages are forwarded
83
+ * unchanged. Providers use this hook for shape conversions such as:
84
+ * - Gemini: hoisting the system message to `systemInstruction`.
85
+ * - Anthropic: injecting an assistant-prefill block for structured output.
86
+ * - OpenAI o-series: merging consecutive same-role messages.
87
+ *
88
+ * Port of Hermes `ProviderProfile.prepare_messages` (Hermes §3.1).
89
+ *
90
+ * @param messages - The transport-level messages prior to provider conversion.
91
+ * @param model - The resolved model identifier.
92
+ * @returns Possibly-modified messages array. Implementations MUST NOT mutate
93
+ * the input array; return a new array if changes are needed.
94
+ */
95
+ readonly prepareMessages?: (messages: readonly TransportMessage[], model: string) => readonly TransportMessage[];
96
+ /**
97
+ * Hook: contribute provider-specific extra body fields.
98
+ *
99
+ * The returned object is merged into the SDK request's `extra_body`
100
+ * (OpenAI-style) or equivalent provider field. Providers use this for:
101
+ * - Gemini: `thinkingConfig` for extended reasoning budget.
102
+ * - OpenRouter: Pareto router plugin parameters.
103
+ * - Anthropic-via-OpenRouter: fine-grained tool streaming control.
104
+ *
105
+ * Port of Hermes `ProviderProfile.build_extra_body`.
106
+ *
107
+ * @param model - The resolved model identifier.
108
+ * @param messages - The transport-level messages at call time.
109
+ * @param tools - The tool definitions at call time.
110
+ * @returns Object merged into the provider request's `extra_body` field.
111
+ */
112
+ readonly buildExtraBody?: (model: string, messages: readonly TransportMessage[], tools: readonly TransportTool[]) => Readonly<Record<string, unknown>>;
113
+ /**
114
+ * Hook: contribute provider-specific top-level API kwargs.
115
+ *
116
+ * The returned object is shallow-merged into the SDK call kwargs. Providers
117
+ * use this for top-level fields that do not fit into `extra_body`:
118
+ * - xAI Grok: `x-grok-conv-id` conversation pinning header.
119
+ * - Kimi: `reasoning_effort` top-level reasoning control.
120
+ * - Moonshot: JSON-schema sanitization applied at the request level.
121
+ *
122
+ * Port of Hermes `ProviderProfile.build_api_kwargs_extras`.
123
+ *
124
+ * @param model - The resolved model identifier.
125
+ * @param messages - The transport-level messages at call time.
126
+ * @param tools - The tool definitions at call time.
127
+ * @returns Object shallow-merged into the SDK call kwargs.
128
+ */
129
+ readonly buildApiKwargsExtras?: (model: string, messages: readonly TransportMessage[], tools: readonly TransportTool[]) => Readonly<Record<string, unknown>>;
130
+ }
131
+ /**
132
+ * Shape that user plugin modules MUST satisfy.
133
+ *
134
+ * A plugin file is any `*.{ts,mjs,js,cjs}` under
135
+ * `${CLEO_HOME}/plugins/model-providers/`. The registry imports it
136
+ * dynamically and calls either its default export or named `register`
137
+ * export with a {@link ProviderPluginApi} instance.
138
+ *
139
+ * @example
140
+ * ```ts
141
+ * // my-plugin.mjs
142
+ * export function register(api) {
143
+ * api.registerProvider({
144
+ * name: 'my-provider',
145
+ * displayName: 'My Provider',
146
+ * authTypes: ['api_key'],
147
+ * baseUrl: 'https://api.myprovider.com',
148
+ * defaultModel: 'my-model-v1',
149
+ * });
150
+ * }
151
+ * ```
152
+ */
153
+ export interface ProviderPlugin {
154
+ /** Called by the registry with access to {@link ProviderPluginApi}. */
155
+ register: (api: ProviderPluginApi) => void;
156
+ }
157
+ /**
158
+ * Minimal surface exposed to plugin modules at load time.
159
+ * Intentionally narrow — plugins should only register providers,
160
+ * not reach into registry internals.
161
+ */
162
+ export interface ProviderPluginApi {
163
+ /** Register a provider profile. Last-writer-wins on name collision. */
164
+ registerProvider: (profile: ProviderProfile) => void;
165
+ }
166
+ //# sourceMappingURL=provider-profile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-profile.d.ts","sourceRoot":"","sources":["../../src/llm/provider-profile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC/E,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEhF;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,IAAI,EAAE,cAAc,GAAG,MAAM,CAAC;IAE9B,0EAA0E;IAC1E,WAAW,EAAE,MAAM,CAAC;IAEpB,qDAAqD;IACrD,SAAS,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAC;IAE7C;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;;;OAIG;IACH,YAAY,EAAE,MAAM,CAAC;IAErB;;;;OAIG;IACH,OAAO,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAEhC;;;;;OAKG;IACH,cAAc,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAElD;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAEhC;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;IAE9F;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,CACzB,QAAQ,EAAE,SAAS,gBAAgB,EAAE,EACrC,KAAK,EAAE,MAAM,KACV,SAAS,gBAAgB,EAAE,CAAC;IAEjC;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,CACxB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,SAAS,gBAAgB,EAAE,EACrC,KAAK,EAAE,SAAS,aAAa,EAAE,KAC5B,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAEvC;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,oBAAoB,CAAC,EAAE,CAC9B,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,SAAS,gBAAgB,EAAE,EACrC,KAAK,EAAE,SAAS,aAAa,EAAE,KAC5B,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACxC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,cAAc;IAC7B,uEAAuE;IACvE,QAAQ,EAAE,CAAC,GAAG,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAC5C;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,uEAAuE;IACvE,gBAAgB,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;CACtD"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * ProviderProfile interface and plugin contracts for the CLEO provider registry.
3
+ *
4
+ * Ported idiomatically from the Hermes provider registry (Python dataclass +
5
+ * importlib pattern → TypeScript interface + dynamic ESM import). This is the
6
+ * canonical type lock for Phase 3 of T-LLM-CRED-CENTRALIZATION — all
7
+ * subsequent Phase 3 tasks depend on this interface shape.
8
+ *
9
+ * @task T9262
10
+ * @epic T9261 (T-LLM-CRED-CENTRALIZATION Phase 3)
11
+ */
12
+ export {};
13
+ //# sourceMappingURL=provider-profile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-profile.js","sourceRoot":"","sources":["../../src/llm/provider-profile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Fully-resolved credential type for the unified LLM provider architecture.
3
+ *
4
+ * This type replaces the partial `CredentialResultWire` at the runtime level.
5
+ * `CredentialResultWire` is retained solely as a wire diagnostic type for
6
+ * `cleo llm whoami` CLI output.
7
+ *
8
+ * @module llm/resolved-credential
9
+ * @task T9281
10
+ * @epic T9261 T-LLM-CRED-CENTRALIZATION
11
+ * @see ADR-072 §Type lock-in
12
+ */
13
+ import type { ProviderId } from './provider-id.js';
14
+ /**
15
+ * Fully-resolved credential ready for use in a transport constructor.
16
+ *
17
+ * The transport consumes this at construction time and MUST NOT store it
18
+ * beyond initialization. {@link extraHeaders} is merged into SDK
19
+ * defaultHeaders.
20
+ *
21
+ * Replaces the partial `CredentialResultWire` for runtime use.
22
+ * `CredentialResultWire` is retained as a wire diagnostic type for
23
+ * `cleo llm whoami` CLI output only.
24
+ *
25
+ * @see ADR-072 §Type lock-in
26
+ */
27
+ export interface ResolvedCredential {
28
+ /** Provider this credential targets. */
29
+ readonly provider: ProviderId;
30
+ /** Human-readable store label (e.g. 'personal', 'work'). */
31
+ readonly label: string;
32
+ /**
33
+ * API key, OAuth bearer token, or empty string for aws_sdk auth.
34
+ * NEVER log this field. NEVER include in NormalizedResponse.providerData.
35
+ */
36
+ readonly token: string;
37
+ /** How the token is presented to the provider. */
38
+ readonly authType: 'api_key' | 'oauth' | 'aws_sdk';
39
+ /**
40
+ * Unix epoch ms at which the token expires. null = never expires.
41
+ * LlmSession checks this before each send() and triggers OAuth refresh
42
+ * when less than 60 seconds remain.
43
+ */
44
+ readonly expiresAt: number | null;
45
+ /**
46
+ * OAuth refresh token. null for api_key and aws_sdk credentials.
47
+ * LlmSession holds this; the transport never sees it.
48
+ */
49
+ readonly refreshToken: string | null;
50
+ /**
51
+ * Extra HTTP headers merged into every SDK request from this credential.
52
+ * Typically carries 'Authorization: Bearer ...' for oauth authType,
53
+ * and 'anthropic-beta: ...' when needed.
54
+ */
55
+ readonly extraHeaders: Readonly<Record<string, string>>;
56
+ /** Base URL override (proxy, on-prem deployment). null = use provider default. */
57
+ readonly baseUrl: string | null;
58
+ /** AWS profile name for Bedrock. null for all other providers. */
59
+ readonly awsProfile: string | null;
60
+ }
61
+ //# sourceMappingURL=resolved-credential.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolved-credential.d.ts","sourceRoot":"","sources":["../../src/llm/resolved-credential.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,kBAAkB;IACjC,wCAAwC;IACxC,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC;IAC9B,4DAA4D;IAC5D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,kDAAkD;IAClD,QAAQ,CAAC,QAAQ,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;IACnD;;;;OAIG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC;;;OAGG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC;;;;OAIG;IACH,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACxD,kFAAkF;IAClF,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,kEAAkE;IAClE,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC"}