@cleocode/contracts 2026.5.62 → 2026.5.63

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/src/config.ts CHANGED
@@ -9,6 +9,8 @@
9
9
  * @task T5710
10
10
  */
11
11
 
12
+ import type { ModelTransport } from './operations/llm.js';
13
+
12
14
  /** Output format options. */
13
15
  export type OutputFormat = 'json' | 'text' | 'jsonl' | 'markdown' | 'table';
14
16
 
@@ -282,7 +284,11 @@ export interface BrainTieringConfig {
282
284
  export interface BrainLlmExtractionConfig {
283
285
  /** Enable LLM-driven extraction gate (default: true). */
284
286
  enabled: boolean;
285
- /** Anthropic model to use for extraction (default: 'claude-haiku-4-5-20251001'). */
287
+ /**
288
+ * Anthropic model to use for extraction. Default lives in
289
+ * `@cleocode/core/llm/role-resolver` (`IMPLICIT_FALLBACK_MODEL`) so the
290
+ * literal stays in a single source location (T9255 grep guard).
291
+ */
286
292
  model: string;
287
293
  /** Minimum importance score (0.0–1.0) below which extractions are dropped (default: 0.6). */
288
294
  minImportance: number;
@@ -325,10 +331,11 @@ export interface BrainConfig {
325
331
  * LLM-driven extraction gate settings.
326
332
  * When enabled and ANTHROPIC_API_KEY is present, session transcripts are
327
333
  * processed by an LLM to extract typed structured memories instead of the
328
- * legacy keyword regex. Defaults are enabled: true and model is the cheap
329
- * Haiku class so extraction cost stays bounded.
334
+ * legacy keyword regex. Defaults are enabled: true and model defaults to
335
+ * the centralised implicit fallback (cheap Haiku class) defined in
336
+ * `@cleocode/core/llm/role-resolver` so extraction cost stays bounded.
330
337
  *
331
- * @defaultValue { enabled: true, model: 'claude-haiku-4-5-20251001', minImportance: 0.6, maxExtractions: 7, maxTranscriptChars: 60000 }
338
+ * @defaultValue { enabled: true, model: IMPLICIT_FALLBACK_MODEL, minImportance: 0.6, maxExtractions: 7, maxTranscriptChars: 60000 }
332
339
  */
333
340
  llmExtraction?: BrainLlmExtractionConfig;
334
341
  }
@@ -381,7 +388,7 @@ export interface DaemonLLMConfig {
381
388
  * LLM provider transport used by daemon loops.
382
389
  * @defaultValue 'anthropic'
383
390
  */
384
- provider: 'anthropic' | 'openai' | 'gemini' | 'moonshot';
391
+ provider: ModelTransport;
385
392
  /**
386
393
  * Full model identifier for the selected provider.
387
394
  * @defaultValue 'claude-sonnet-4-6'
@@ -389,14 +396,85 @@ export interface DaemonLLMConfig {
389
396
  model: string;
390
397
  }
391
398
 
399
+ /**
400
+ * Canonical model transport identifier — re-export of {@link ModelTransport}
401
+ * from `operations/llm.ts` so config-layer types stay in lock-step with the
402
+ * operations layer with no risk of drift.
403
+ *
404
+ * Previously declared as a separate string-literal union; collapsed in the
405
+ * T-LLM-CRED Phase 2 DRY/SOLID review (P1-2). Adding a new transport now
406
+ * requires editing only `operations/llm.ts`.
407
+ *
408
+ * @task T-LLM-CRED-CENTRALIZATION Phase 2 — DRY review P1-2
409
+ */
410
+ export type LlmTransport = ModelTransport;
411
+
412
+ /**
413
+ * Logical LLM role name used by role-aware resolvers (BRAIN, sentient, etc.).
414
+ *
415
+ * Each role can pin its own provider + model + credential label, with
416
+ * resolution falling back to `LlmConfig.default` and finally to the legacy
417
+ * `LlmConfig.daemon` block.
418
+ *
419
+ * @task T-LLM-CRED-CENTRALIZATION Phase 2 (T9256)
420
+ */
421
+ export type RoleName = 'extraction' | 'consolidation' | 'derivation' | 'hygiene' | 'judgement';
422
+
423
+ /**
424
+ * Canonical default LLM target for unscoped (non-role) calls.
425
+ *
426
+ * Replaces the role previously played by `LlmConfig.daemon`. The `daemon`
427
+ * field stays as a deprecated alias for one release cycle to give downstream
428
+ * consumers time to migrate.
429
+ *
430
+ * @task T-LLM-CRED-CENTRALIZATION Phase 2 (T9256)
431
+ */
432
+ export interface LlmDefaultConfig {
433
+ /** LLM provider transport for the default model. */
434
+ provider: LlmTransport;
435
+ /** Full model identifier for the selected provider. */
436
+ model: string;
437
+ }
438
+
439
+ /**
440
+ * Per-role LLM configuration entry.
441
+ *
442
+ * Each role may optionally pin to a specific credential label (matching a
443
+ * `CredentialResult.label`) so that, e.g., the `extraction` role can use a
444
+ * different Anthropic API key than `judgement` without changing the global
445
+ * default.
446
+ *
447
+ * @task T-LLM-CRED-CENTRALIZATION Phase 2 (T9256)
448
+ */
449
+ export interface LlmRoleConfig {
450
+ /** LLM provider transport for this role. */
451
+ provider: LlmTransport;
452
+ /** Full model identifier for the selected provider. */
453
+ model: string;
454
+ /**
455
+ * Optional credential label to pin this role to a specific credential
456
+ * entry resolved by `resolveCredentials()`. When omitted, the role
457
+ * inherits the default credential resolution order.
458
+ */
459
+ credentialLabel?: string;
460
+ }
461
+
392
462
  /**
393
463
  * Top-level LLM configuration block inside CleoConfig.
394
464
  *
395
465
  * Stored at `llm` in config.json.
466
+ *
467
+ * Resolution order for role-scoped calls:
468
+ * `roles[role]` → `default` → `daemon` (legacy).
396
469
  */
397
470
  export interface LlmConfig {
398
471
  /**
399
472
  * Daemon LLM settings (provider + model for background loops).
473
+ *
474
+ * @deprecated Use `default` instead. Retained as a fallback alias for
475
+ * one release cycle (T-LLM-CRED-CENTRALIZATION Phase 2 · T9256). New
476
+ * code must read `default` first and only fall through to `daemon` when
477
+ * `default` is absent.
400
478
  * @defaultValue { provider: 'anthropic', model: 'claude-sonnet-4-6' }
401
479
  */
402
480
  daemon?: DaemonLLMConfig;
@@ -405,6 +483,23 @@ export interface LlmConfig {
405
483
  * Keys are provider names: 'anthropic' | 'openai' | 'gemini' | 'moonshot'.
406
484
  */
407
485
  providers?: Record<string, LlmProviderEntry>;
486
+ /**
487
+ * Canonical default LLM for unscoped calls. Replaces the role previously
488
+ * played by `daemon`, which stays as a deprecated alias for one release
489
+ * cycle.
490
+ *
491
+ * @task T-LLM-CRED-CENTRALIZATION Phase 2 (T9256)
492
+ */
493
+ default?: LlmDefaultConfig;
494
+ /**
495
+ * Per-role LLM overrides. Each role optionally pins to a credential
496
+ * label.
497
+ *
498
+ * Resolution order: `roles[role]` → `default` → `daemon` (legacy).
499
+ *
500
+ * @task T-LLM-CRED-CENTRALIZATION Phase 2 (T9256)
501
+ */
502
+ roles?: Partial<Record<RoleName, LlmRoleConfig>>;
408
503
  }
409
504
 
410
505
  /** SignalDock transport mode. */
package/src/index.ts CHANGED
@@ -219,7 +219,10 @@ export type {
219
219
  LifecycleConfig,
220
220
  LifecycleEnforcementMode,
221
221
  LlmConfig,
222
+ LlmDefaultConfig,
222
223
  LlmProviderEntry,
224
+ LlmRoleConfig,
225
+ LlmTransport,
223
226
  LoggingConfig,
224
227
  LogLevel,
225
228
  MemoryBridgeMode,
@@ -227,6 +230,7 @@ export type {
227
230
  OutputFormat,
228
231
  ProviderConfig,
229
232
  ResolvedValue,
233
+ RoleName,
230
234
  SessionConfig,
231
235
  SessionSummaryInput,
232
236
  SharingConfig,
@@ -614,6 +618,35 @@ export type {
614
618
  LifecycleStatusResult,
615
619
  StageRecord,
616
620
  } from './operations/lifecycle.js';
621
+ // === LLM Credential + Role-Resolver Wire Types (T-LLM-CRED Phase 1/2 — T9255) ===
622
+ export type {
623
+ AuthTypeWire,
624
+ CredentialResultWire,
625
+ CredentialSourceWire,
626
+ CredentialsStoreStrategyWire,
627
+ // `cleo llm` CLI / dispatch operation contracts (T9258)
628
+ LlmAddParams,
629
+ LlmAddResult,
630
+ LlmListParams,
631
+ LlmListResult,
632
+ LlmProfileParams,
633
+ LlmProfileResult,
634
+ LlmRemoveParams,
635
+ LlmRemoveResult,
636
+ LlmStoredCredentialView,
637
+ LlmTestParams,
638
+ LlmTestResult,
639
+ LlmUseParams,
640
+ LlmUseResult,
641
+ LlmWhoamiEntry,
642
+ LlmWhoamiParams,
643
+ LlmWhoamiResult,
644
+ ModelTransport,
645
+ ResolutionSource,
646
+ ResolvedLLM,
647
+ ResolveLLMForRoleOptions,
648
+ StoredAuthTypeWire,
649
+ } from './operations/llm.js';
617
650
  // Multi-pass retrieval bundle types (PSYCHE Wave 4 · T1090)
618
651
  export type {
619
652
  PassMask,
@@ -56,6 +56,15 @@ export interface ModelConfig {
56
56
  cachePolicy?: PromptCachePolicy | null;
57
57
  /** Fallback model config used on final retry attempt. */
58
58
  fallback?: Omit<ModelConfig, 'fallback'> | null;
59
+ /**
60
+ * Extra HTTP headers to attach to the provider client (merged into the SDK's
61
+ * `defaultHeaders`). Populated from `authHeaders(cred)` when a credential is
62
+ * resolved with `authType: 'oauth'` so the provider client uses the
63
+ * `Authorization: Bearer …` scheme instead of `x-api-key`.
64
+ *
65
+ * @task T-LLM-CRED-CENTRALIZATION Phase 1
66
+ */
67
+ extraHeaders?: Record<string, string> | null;
59
68
  }
60
69
 
61
70
  /** Parameters for a single LLM call. */
@@ -113,3 +122,431 @@ export interface LLMCallResult<T = string> {
113
122
  thinkingBlocks: Array<Record<string, unknown>>;
114
123
  reasoningDetails: Array<Record<string, unknown>>;
115
124
  }
125
+
126
+ // ============================================================================
127
+ // Credential resolution wire types (T-LLM-CRED-CENTRALIZATION Phase 1/2)
128
+ //
129
+ // These mirror the runtime types declared in `@cleocode/core/llm/credentials.ts`
130
+ // but live here so packages outside `core` (CLI, harness, studio) can speak
131
+ // the same wire vocabulary without taking a dependency on core internals.
132
+ // The runtime module re-exports compatible aliases so existing imports keep
133
+ // working.
134
+ // ============================================================================
135
+
136
+ /**
137
+ * Which credential-resolution tier produced a {@link CredentialResultWire}.
138
+ *
139
+ * Mirrors `CredentialSource` in `@cleocode/core/llm/credentials.ts`. The set is
140
+ * append-only; new tiers (e.g. `aws-sdk`, `gcp-sdk` in Phase 3) extend this
141
+ * union.
142
+ *
143
+ * @task T-LLM-CRED-CENTRALIZATION Phase 1
144
+ * @task T9255
145
+ */
146
+ export type CredentialSourceWire =
147
+ | 'explicit'
148
+ | 'env'
149
+ | 'cred-file'
150
+ | 'claude-creds'
151
+ | 'global-config'
152
+ | 'project-config';
153
+
154
+ /**
155
+ * Authentication scheme used when sending the credential to the provider.
156
+ *
157
+ * - `api_key` — provider-issued long-lived key sent as `x-api-key` (Anthropic)
158
+ * or `Authorization: Bearer …` (OpenAI, Gemini, Moonshot).
159
+ * - `oauth` — short-lived OAuth bearer token sent as `Authorization: Bearer …`
160
+ * with the matching beta header.
161
+ *
162
+ * @task T-LLM-CRED-CENTRALIZATION Phase 1
163
+ * @task T9255
164
+ */
165
+ export type AuthTypeWire = 'api_key' | 'oauth';
166
+
167
+ /**
168
+ * Resolved credential as returned by `resolveCredentials()` /
169
+ * `resolveLLMForRole()`. Mirrors `CredentialResult` in core. Compatible by
170
+ * structural typing.
171
+ *
172
+ * @task T-LLM-CRED-CENTRALIZATION Phase 1
173
+ * @task T9255
174
+ */
175
+ export interface CredentialResultWire {
176
+ /** Provider transport this credential is for. */
177
+ provider: ModelTransport;
178
+ /** API key or OAuth bearer token. `null` only when no credential was found. */
179
+ apiKey: string | null;
180
+ /** Which tier produced this credential. `undefined` when `apiKey` is `null`. */
181
+ source: CredentialSourceWire | undefined;
182
+ /** Scheme used to present the credential to the provider. */
183
+ authType: AuthTypeWire;
184
+ }
185
+
186
+ // ============================================================================
187
+ // Role-based LLM resolution wire types (T9255 — Phase 2 T-llm-1)
188
+ // ============================================================================
189
+
190
+ /**
191
+ * Which configuration tier produced a {@link ResolvedLLM}.
192
+ *
193
+ * Resolution chain order:
194
+ * 1. `role` — `config.llm.roles[role]` (explicit override)
195
+ * 2. `default` — `config.llm.default` (canonical default)
196
+ * 3. `daemon-legacy` — `config.llm.daemon` (deprecated alias)
197
+ * 4. `implicit-fallback` — hard-coded fallback inside the resolver
198
+ *
199
+ * Useful for `cleo llm whoami` diagnostics and for migration tooling that
200
+ * needs to identify call-sites still on the legacy `daemon` block.
201
+ *
202
+ * @task T9255
203
+ */
204
+ export type ResolutionSource = 'role' | 'default' | 'daemon-legacy' | 'implicit-fallback';
205
+
206
+ /**
207
+ * Result envelope returned by `resolveLLMForRole(role)`.
208
+ *
209
+ * Carries the fully-wired SDK client plus the {@link CredentialResultWire}
210
+ * so raw-fetch callers (sleep-consolidation, observer-reflector, hygiene-scan)
211
+ * can call `authHeaders(credential)` themselves when bypassing the SDK
212
+ * client (e.g. to call the Anthropic Messages REST API directly).
213
+ *
214
+ * `client` is `null` only when `credential.apiKey` is also `null` — in which
215
+ * case the caller MUST fall back to its graceful-degradation path
216
+ * (`return null` / skip / log warn).
217
+ *
218
+ * `client` is typed as `unknown` here because the concrete SDK classes
219
+ * (Anthropic, OpenAI, GoogleGenerativeAI) are not referenced from contracts
220
+ * to preserve its zero-dependency footprint. Consumers MUST narrow via the
221
+ * typed helpers in `@cleocode/core/llm/role-resolver` (e.g.
222
+ * `resolveAnthropicForRole`) rather than casting with `as unknown as X`.
223
+ *
224
+ * @task T9255
225
+ */
226
+ export interface ResolvedLLM {
227
+ /** LLM provider transport that was resolved. */
228
+ provider: ModelTransport;
229
+ /** Full model identifier. */
230
+ model: string;
231
+ /**
232
+ * Fully-wired SDK client constructed via `clientForModelConfig`. `null`
233
+ * when no credential is available. Typed as `unknown` — consumers MUST
234
+ * narrow via a provider-specific helper (e.g. `resolveAnthropicForRole`
235
+ * in `@cleocode/core/llm/role-resolver`), NEVER via an `as unknown as X`
236
+ * cast.
237
+ */
238
+ client: unknown;
239
+ /**
240
+ * Resolved credential. `null` when no tier produced a token. Callers
241
+ * MUST handle this case.
242
+ */
243
+ credential: CredentialResultWire | null;
244
+ /** Which config path produced this resolution. */
245
+ source: ResolutionSource;
246
+ /** When `roles[role].credentialLabel` was set, the label that was used. */
247
+ credentialLabel?: string;
248
+ }
249
+
250
+ /**
251
+ * Options accepted by `resolveLLMForRole()`.
252
+ *
253
+ * @task T9255
254
+ */
255
+ export interface ResolveLLMForRoleOptions {
256
+ /**
257
+ * Absolute path to the project root. Forwarded to `loadConfig()` and to
258
+ * `resolveCredentials({ projectRoot })` for tier-5 project-config lookup.
259
+ * Defaults to `process.cwd()`.
260
+ */
261
+ projectRoot?: string;
262
+ }
263
+
264
+ // ============================================================================
265
+ // `cleo llm` CLI / dispatch operation contracts (T9258 — Phase 2 T-llm-4)
266
+ //
267
+ // Wire types backing the `cleo llm` CLI subcommands and the `llm` dispatch
268
+ // domain. Provider-redacted views of `StoredCredential` (defined in
269
+ // `@cleocode/core/llm/credentials-store`) plus the dispatch param/result
270
+ // shapes for add / list / remove / use / profile / test / whoami.
271
+ //
272
+ // Tokens are NEVER returned in raw form by these envelopes — `tokenPreview`
273
+ // surfaces only the last 4 characters so the wire vocabulary is safe for
274
+ // JSON output, logs, and remote dispatch consumers.
275
+ // ============================================================================
276
+
277
+ /**
278
+ * Storage-level authentication scheme as persisted in the credentials store.
279
+ *
280
+ * Wider than the wire-level {@link AuthTypeWire}: includes `'aws_sdk'` for
281
+ * Bedrock / Vertex entries where the AWS SDK supplies the credential
282
+ * out-of-band. The runtime resolver narrows `'aws_sdk' → 'api_key'` for
283
+ * wire-level use until Phase 3 widens {@link AuthTypeWire}.
284
+ *
285
+ * Mirrors `StoredAuthType` in `@cleocode/core/llm/credentials-store`.
286
+ *
287
+ * @task T9258
288
+ */
289
+ export type StoredAuthTypeWire = 'api_key' | 'oauth' | 'aws_sdk';
290
+
291
+ /**
292
+ * Strategy used by the credentials-store picker.
293
+ *
294
+ * Mirrors `CredentialsStoreStrategy` in
295
+ * `@cleocode/core/llm/credentials-store`. Held here so callers outside
296
+ * `core` can render UI without taking a dependency on the storage module.
297
+ *
298
+ * @task T9258
299
+ */
300
+ export type CredentialsStoreStrategyWire = 'priorityWithFallback' | 'roundRobin' | 'priorityOnly';
301
+
302
+ /**
303
+ * Token-redacted view of a single stored credential.
304
+ *
305
+ * `tokenPreview` is the last 4 characters of `accessToken` prefixed by
306
+ * `'…'` (e.g. `'…aB7q'`). The full token is NEVER returned by any
307
+ * `cleo llm` operation — callers that need the live token must resolve it
308
+ * through `resolveLLMForRole()`.
309
+ *
310
+ * @task T9258
311
+ */
312
+ export interface LlmStoredCredentialView {
313
+ /** LLM transport this credential is for. */
314
+ provider: ModelTransport;
315
+ /** Human-readable identifier, unique within `provider`. */
316
+ label: string;
317
+ /** Storage-level auth scheme. */
318
+ authType: StoredAuthTypeWire;
319
+ /** Redacted token preview — last 4 chars, prefixed by `'…'`. */
320
+ tokenPreview: string;
321
+ /** Whether the entry carried a non-empty refresh token. */
322
+ hasRefreshToken: boolean;
323
+ /** Unix epoch ms; `null` means "never expires". */
324
+ expiresAt: number | null;
325
+ /** Lower wins. */
326
+ priority: number;
327
+ /** Free-form provenance label (`claude-code`, `cli-input`, etc.). */
328
+ source: string | undefined;
329
+ /** Optional override for provider base URL. */
330
+ baseUrl: string | null;
331
+ /** When `true`, the picker skips this entry. */
332
+ disabled: boolean;
333
+ }
334
+
335
+ /**
336
+ * Parameters for `llm.add` (mutate).
337
+ *
338
+ * Mirrors the `cleo llm add <provider> --api-key <k>` CLI surface. When
339
+ * `authType` is omitted, the dispatcher auto-detects from the token
340
+ * prefix: tokens beginning with `sk-ant-oat-` are stored as `'oauth'`,
341
+ * everything else as `'api_key'`.
342
+ *
343
+ * @task T9258
344
+ */
345
+ export interface LlmAddParams {
346
+ /** Target provider transport. */
347
+ provider: ModelTransport;
348
+ /** API key or OAuth bearer token to persist. */
349
+ apiKey: string;
350
+ /** Human-readable label, unique within `provider`. Defaults to `'default'`. */
351
+ label?: string;
352
+ /** Optional override for the provider base URL. */
353
+ baseUrl?: string;
354
+ /** Optional explicit auth type override (skips prefix auto-detect). */
355
+ authType?: StoredAuthTypeWire;
356
+ /** Optional priority override (lower wins). */
357
+ priority?: number;
358
+ }
359
+
360
+ /**
361
+ * Result envelope for `llm.add`.
362
+ *
363
+ * @task T9258
364
+ */
365
+ export interface LlmAddResult {
366
+ /** Token-redacted view of the newly stored entry. */
367
+ credential: LlmStoredCredentialView;
368
+ /** Detected auth type (`'oauth'` for `sk-ant-oat-*`, else `'api_key'`). */
369
+ detectedAuthType: StoredAuthTypeWire;
370
+ }
371
+
372
+ /**
373
+ * Parameters for `llm.list` (query).
374
+ *
375
+ * @task T9258
376
+ */
377
+ export interface LlmListParams {
378
+ /** Optional provider filter — when set, only entries for that provider. */
379
+ provider?: ModelTransport;
380
+ }
381
+
382
+ /**
383
+ * Result envelope for `llm.list`.
384
+ *
385
+ * @task T9258
386
+ */
387
+ export interface LlmListResult {
388
+ /** Token-redacted credentials, in store order (priority asc). */
389
+ credentials: LlmStoredCredentialView[];
390
+ }
391
+
392
+ /**
393
+ * Parameters for `llm.remove` (mutate).
394
+ *
395
+ * @task T9258
396
+ */
397
+ export interface LlmRemoveParams {
398
+ /** Target provider transport. */
399
+ provider: ModelTransport;
400
+ /** Label of the credential to remove. */
401
+ label: string;
402
+ }
403
+
404
+ /**
405
+ * Result envelope for `llm.remove`.
406
+ *
407
+ * @task T9258
408
+ */
409
+ export interface LlmRemoveResult {
410
+ /** `true` when a matching entry was deleted. */
411
+ removed: boolean;
412
+ /** Echo of the targeted `(provider, label)` pair. */
413
+ provider: ModelTransport;
414
+ /** Echo of the targeted label. */
415
+ label: string;
416
+ }
417
+
418
+ /**
419
+ * Parameters for `llm.use` (mutate) — set `llm.default.{provider,model}`.
420
+ *
421
+ * @task T9258
422
+ */
423
+ export interface LlmUseParams {
424
+ /** Provider transport to mark as the default. */
425
+ provider: ModelTransport;
426
+ /** Optional default model identifier. When omitted, `default.model` is left untouched. */
427
+ model?: string;
428
+ }
429
+
430
+ /**
431
+ * Result envelope for `llm.use`.
432
+ *
433
+ * @task T9258
434
+ */
435
+ export interface LlmUseResult {
436
+ /** Provider written to `llm.default.provider`. */
437
+ provider: ModelTransport;
438
+ /** Model written to `llm.default.model` — `null` when not provided. */
439
+ model: string | null;
440
+ /** Config scope the write landed in (`'global'` for `cleo llm use`). */
441
+ scope: 'project' | 'global';
442
+ }
443
+
444
+ /**
445
+ * Parameters for `llm.profile` (mutate) — set `llm.roles[role]`.
446
+ *
447
+ * @task T9258
448
+ */
449
+ export interface LlmProfileParams {
450
+ /** Logical role name. */
451
+ role: string;
452
+ /** Provider transport for this role. */
453
+ provider: ModelTransport;
454
+ /** Optional model identifier for this role. */
455
+ model?: string;
456
+ /** Optional credential label to pin this role to a specific store entry. */
457
+ credentialLabel?: string;
458
+ }
459
+
460
+ /**
461
+ * Result envelope for `llm.profile`.
462
+ *
463
+ * @task T9258
464
+ */
465
+ export interface LlmProfileResult {
466
+ /** Role name written to `llm.roles[role]`. */
467
+ role: string;
468
+ /** Provider written for the role. */
469
+ provider: ModelTransport;
470
+ /** Model written for the role (or `null` when not supplied). */
471
+ model: string | null;
472
+ /** Credential label written for the role (or `null` when not supplied). */
473
+ credentialLabel: string | null;
474
+ /** Config scope the write landed in. */
475
+ scope: 'project' | 'global';
476
+ }
477
+
478
+ /**
479
+ * Parameters for `llm.test` (query).
480
+ *
481
+ * @task T9258
482
+ */
483
+ export interface LlmTestParams {
484
+ /** Provider transport to test. */
485
+ provider: ModelTransport;
486
+ /** Optional credential label to pin the test to a specific store entry. */
487
+ label?: string;
488
+ /** Optional model override. Defaults to the provider's implicit fallback. */
489
+ model?: string;
490
+ }
491
+
492
+ /**
493
+ * Result envelope for `llm.test`. Tokens are NEVER included.
494
+ *
495
+ * @task T9258
496
+ */
497
+ export interface LlmTestResult {
498
+ /** Provider transport that was probed. */
499
+ provider: ModelTransport;
500
+ /** Model identifier used for the probe. */
501
+ model: string;
502
+ /** End-to-end round-trip latency in ms. */
503
+ latencyMs: number;
504
+ /** Provider response identifier (e.g. Anthropic `msg_…`). `null` when unavailable. */
505
+ providerResponseId: string | null;
506
+ /** Redacted credential preview (last 4 chars) — confirms which entry was used. */
507
+ credentialPreview: string;
508
+ /** Resolution tier that produced the credential (`env`, `cred-file`, etc.). */
509
+ credentialSource: CredentialSourceWire;
510
+ }
511
+
512
+ /**
513
+ * Single `whoami` row — one entry per `RoleName`.
514
+ *
515
+ * @task T9258
516
+ */
517
+ export interface LlmWhoamiEntry {
518
+ /** Role name (`'extraction' | 'consolidation' | ...`). */
519
+ role: string;
520
+ /** Provider that would be picked for this role. */
521
+ provider: ModelTransport;
522
+ /** Model that would be used. */
523
+ model: string;
524
+ /** Which config tier produced the resolution. */
525
+ source: ResolutionSource;
526
+ /** Credential label, when the role pinned a specific store entry. */
527
+ credentialLabel: string | undefined;
528
+ /** Resolution tier of the eventual credential, when one was reachable. */
529
+ credentialSource: CredentialSourceWire | undefined;
530
+ /** Whether a usable credential exists for this role. */
531
+ hasCredential: boolean;
532
+ }
533
+
534
+ /**
535
+ * Parameters for `llm.whoami` (query). Reserved for future filters.
536
+ *
537
+ * @task T9258
538
+ */
539
+ export interface LlmWhoamiParams {
540
+ /** Optional role filter — when set, only that role is resolved. */
541
+ role?: string;
542
+ }
543
+
544
+ /**
545
+ * Result envelope for `llm.whoami`.
546
+ *
547
+ * @task T9258
548
+ */
549
+ export interface LlmWhoamiResult {
550
+ /** One entry per role resolved (filtered by `params.role` when set). */
551
+ entries: LlmWhoamiEntry[];
552
+ }