@cleocode/contracts 2026.5.68 → 2026.5.69

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 (51) hide show
  1. package/dist/__tests__/credentials.test.d.ts +10 -0
  2. package/dist/__tests__/credentials.test.d.ts.map +1 -0
  3. package/dist/__tests__/credentials.test.js +100 -0
  4. package/dist/__tests__/credentials.test.js.map +1 -0
  5. package/dist/__tests__/llm-config-schema.test.d.ts +6 -6
  6. package/dist/__tests__/llm-config-schema.test.js +9 -13
  7. package/dist/__tests__/llm-config-schema.test.js.map +1 -1
  8. package/dist/config.d.ts +32 -54
  9. package/dist/config.d.ts.map +1 -1
  10. package/dist/credentials.d.ts +75 -0
  11. package/dist/credentials.d.ts.map +1 -0
  12. package/dist/credentials.js +79 -0
  13. package/dist/credentials.js.map +1 -0
  14. package/dist/index.d.ts +9 -3
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +2 -0
  17. package/dist/index.js.map +1 -1
  18. package/dist/llm/failover-reason.d.ts +1 -1
  19. package/dist/llm/interfaces.d.ts +1 -42
  20. package/dist/llm/interfaces.d.ts.map +1 -1
  21. package/dist/llm/oauth.d.ts +125 -0
  22. package/dist/llm/oauth.d.ts.map +1 -0
  23. package/dist/llm/oauth.js +12 -0
  24. package/dist/llm/oauth.js.map +1 -0
  25. package/dist/llm/plugin-llm.d.ts +93 -0
  26. package/dist/llm/plugin-llm.d.ts.map +1 -0
  27. package/dist/llm/plugin-llm.js +65 -0
  28. package/dist/llm/plugin-llm.js.map +1 -0
  29. package/dist/llm/provider-profile.d.ts +13 -0
  30. package/dist/llm/provider-profile.d.ts.map +1 -1
  31. package/dist/memory/context-engine.d.ts +67 -0
  32. package/dist/memory/context-engine.d.ts.map +1 -0
  33. package/dist/memory/context-engine.js +15 -0
  34. package/dist/memory/context-engine.js.map +1 -0
  35. package/dist/operations/llm.d.ts +43 -6
  36. package/dist/operations/llm.d.ts.map +1 -1
  37. package/dist/operations/llm.js +0 -4
  38. package/dist/operations/llm.js.map +1 -1
  39. package/package.json +10 -2
  40. package/src/__tests__/credentials.test.ts +122 -0
  41. package/src/__tests__/llm-config-schema.test.ts +9 -13
  42. package/src/config.ts +37 -55
  43. package/src/credentials.ts +114 -0
  44. package/src/index.ts +22 -8
  45. package/src/llm/failover-reason.ts +1 -1
  46. package/src/llm/interfaces.ts +10 -44
  47. package/src/llm/oauth.ts +144 -0
  48. package/src/llm/plugin-llm.ts +128 -0
  49. package/src/llm/provider-profile.ts +14 -0
  50. package/src/memory/context-engine.ts +78 -0
  51. package/src/operations/llm.ts +50 -6
package/src/index.ts CHANGED
@@ -210,7 +210,6 @@ export type {
210
210
  ClaudeSpawnMode,
211
211
  CleoConfig,
212
212
  ConfigSource,
213
- DaemonLLMConfig,
214
213
  DateFormat,
215
214
  DecisionsConfig,
216
215
  DepsRequiredAt,
@@ -221,8 +220,8 @@ export type {
221
220
  LlmConfig,
222
221
  LlmDefaultConfig,
223
222
  LlmProviderEntry,
223
+ LlmProviderTransport,
224
224
  LlmRoleConfig,
225
- LlmTransport,
226
225
  LoggingConfig,
227
226
  LogLevel,
228
227
  MemoryBridgeMode,
@@ -239,6 +238,12 @@ export type {
239
238
  SignalDockMode,
240
239
  } from './config.js';
241
240
  export type { AdapterContextMonitorProvider } from './context-monitor.js';
241
+ // === Claude Code credential parsing (T9307 — pure helper, no core imports) ===
242
+ export type {
243
+ ClaudeCodeOAuthBlock,
244
+ ParsedClaudeCodeCredential,
245
+ } from './credentials.js';
246
+ export { parseClaudeCodeCredentials } from './credentials.js';
242
247
  // === DataAccessor Interface ===
243
248
  export type {
244
249
  ArchiveFields,
@@ -431,7 +436,6 @@ export type { ClassifiedError, FailoverReason } from './llm/failover-reason.js';
431
436
  // === Phase 4 Unified Architecture (T9281 / ADR-072) — Session + Executor interfaces ===
432
437
  export type {
433
438
  AggregatedUsage,
434
- ContextEngine,
435
439
  ExecutionEvent,
436
440
  ExecutionRequest,
437
441
  ExecutorFactoryOptions,
@@ -447,11 +451,11 @@ export type {
447
451
  TransportContext,
448
452
  } from './llm/interfaces.js';
449
453
  // === Normalized LLM Transport Types (T9263 — Phase 3 T-LLM-CRED) ===
450
- // Note: LlmTransport (the interface) is intentionally NOT re-exported at the
451
- // top level here because `config.ts` already exports `LlmTransport` as a type
452
- // alias for `ModelTransport`. Consumers that need the transport interface
453
- // should import the LlmTransport interface from the llm/normalized-response.js
454
- // subpath rather than the package root.
454
+ // Note: LlmTransport (the wire-level interface from normalized-response.ts) is
455
+ // intentionally NOT re-exported at the top level here. The config-layer alias
456
+ // was renamed LlmProviderTransport (T9308) to eliminate the name collision.
457
+ // Consumers that need the transport interface should import LlmTransport from
458
+ // the llm/normalized-response.js subpath rather than the package root.
455
459
  export type {
456
460
  NormalizedResponse,
457
461
  NormalizedToolCall,
@@ -460,6 +464,11 @@ export type {
460
464
  TransportRequest,
461
465
  TransportTool,
462
466
  } from './llm/normalized-response.js';
467
+ // === OAuth types — SSoT shared between core and cleo (T9302) ===
468
+ export type { OAuthMode, OAuthTokens, PkceFlowConfig, ProviderOAuthConfig } from './llm/oauth.js';
469
+ // === Phase 4 Plugin LLM facade types (T9305) ===
470
+ export type { PluginLlmComplete, PluginLlmContext } from './llm/plugin-llm.js';
471
+ export { PluginLlmError, PluginModelGateError } from './llm/plugin-llm.js';
463
472
  // === Phase 4 Unified Architecture (T9281 / ADR-072) — Provider identity ===
464
473
  export type { ApiMode, BuiltinProviderId, ProviderId } from './llm/provider-id.js';
465
474
  // === Provider Profile + Plugin Contracts (T9262 — Phase 3 T-LLM-CRED) ===
@@ -470,6 +479,8 @@ export type {
470
479
  } from './llm/provider-profile.js';
471
480
  // === Phase 4 Unified Architecture (T9281 / ADR-072) — Resolved credential ===
472
481
  export type { ResolvedCredential } from './llm/resolved-credential.js';
482
+ // === ContextEngine contract (canonical home — T9304) ===
483
+ export type { CompressedContext, ContextEngine } from './memory/context-engine.js';
473
484
  export type {
474
485
  BridgeDecision,
475
486
  BridgeLearning,
@@ -675,8 +686,11 @@ export type {
675
686
  LlmListResult,
676
687
  LlmProfileParams,
677
688
  LlmProfileResult,
689
+ LlmProviderSourceWire,
690
+ LlmProviderStatusEntry,
678
691
  LlmRemoveParams,
679
692
  LlmRemoveResult,
693
+ LlmStatusResult,
680
694
  LlmStoredCredentialView,
681
695
  LlmTestParams,
682
696
  LlmTestResult,
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Structured taxonomy of LLM failure modes — mirrors Hermes' FailoverReason enum.
3
3
  *
4
- * Consumers (CredentialPool, auxiliary-router, CLI error envelopes) use this
4
+ * Consumers (CredentialPool, ConcreteSession, CLI error envelopes) use this
5
5
  * to drive deterministic recovery actions instead of ad-hoc status-code
6
6
  * inspection.
7
7
  *
@@ -32,6 +32,12 @@ import type {
32
32
  } from './normalized-response.js';
33
33
  import type { ProviderId } from './provider-id.js';
34
34
 
35
+ // Re-export canonical ContextEngine types from their new home in memory/.
36
+ // The definition was moved to packages/contracts/src/memory/context-engine.ts
37
+ // (T9304) so that the memory package can import it without a circular dep on
38
+ // the llm/ subtree. This re-export preserves back-compat for all existing
39
+ // consumers that import ContextEngine from llm/interfaces.js.
40
+ export type { CompressedContext, ContextEngine } from '../memory/context-engine.js';
35
41
  // Re-export LlmTransport so consumers of this module can reference it without
36
42
  // an additional import from normalized-response.js.
37
43
  export type { LlmTransport };
@@ -391,51 +397,11 @@ export interface ExecutionRequest {
391
397
  }
392
398
 
393
399
  // ---------------------------------------------------------------------------
394
- // Context engine
400
+ // Context engine (canonical definition: packages/contracts/src/memory/context-engine.ts)
395
401
  // ---------------------------------------------------------------------------
396
-
397
- /**
398
- * Optional context-compression engine supplied to {@link LlmExecutor}.
399
- *
400
- * When present, the executor calls {@link shouldCompress} after each model
401
- * turn. If it returns `true`, the executor calls {@link compress} to reduce
402
- * the session history before the next iteration, then emits a
403
- * `context_compressed` event.
404
- *
405
- * When absent (undefined), the executor skips all compression checks silently.
406
- *
407
- * @see ADR-072 §"LlmExecutor — agent-loop level"
408
- */
409
- export interface ContextEngine {
410
- /**
411
- * Returns `true` when the current history warrants compression.
412
- *
413
- * @param history - Current read-only conversation history snapshot.
414
- * @returns Whether compression should be applied before the next model turn.
415
- */
416
- shouldCompress(history: readonly TransportMessage[]): boolean;
417
- /**
418
- * Compresses the session history in-place (or returns a compressed copy).
419
- *
420
- * The executor replaces the session history with the returned messages after
421
- * calling this method. It also emits a `context_compressed` event carrying
422
- * the token counts before and after.
423
- *
424
- * @param history - Current read-only conversation history snapshot.
425
- * @returns The compressed message array.
426
- */
427
- compress(history: readonly TransportMessage[]): Promise<TransportMessage[]>;
428
- /**
429
- * Estimate token count for a history snapshot.
430
- *
431
- * Used by the executor to populate {@link ExecutionEvent} `tokensBefore` /
432
- * `tokensAfter` fields. May be an approximation (e.g. character / 4).
433
- *
434
- * @param history - Conversation history snapshot to measure.
435
- * @returns Estimated token count.
436
- */
437
- estimateTokens(history: readonly TransportMessage[]): number;
438
- }
402
+ // ContextEngine and CompressedContext are re-exported above from their new
403
+ // canonical location. This section is intentionally empty — see the re-export
404
+ // near the top of this file.
439
405
 
440
406
  // ---------------------------------------------------------------------------
441
407
  // Executor interface
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Shared OAuth type contracts for the CLEO LLM credential layer.
3
+ *
4
+ * Defines the SSoT types shared between `@cleocode/core` (PKCE implementation)
5
+ * and `@cleocode/cleo` (CLI dispatcher). No runtime dependencies — types only.
6
+ *
7
+ * @module contracts/llm/oauth
8
+ * @task T9302
9
+ * @epic T9261 T-LLM-CRED-CENTRALIZATION
10
+ */
11
+
12
+ // ---------------------------------------------------------------------------
13
+ // OAuth mode discriminant
14
+ // ---------------------------------------------------------------------------
15
+
16
+ /**
17
+ * OAuth grant mode supported by a provider profile.
18
+ *
19
+ * - `pkce` — RFC 7636 Authorization Code + PKCE (browser-based or headless
20
+ * with manual code paste). Used by Anthropic.
21
+ * - `device-code` — RFC 8628 Device Authorization Grant (polling). Used by
22
+ * Kimi Code.
23
+ */
24
+ export type OAuthMode = 'pkce' | 'device-code';
25
+
26
+ // ---------------------------------------------------------------------------
27
+ // Token response
28
+ // ---------------------------------------------------------------------------
29
+
30
+ /**
31
+ * Successful token response from an OAuth token endpoint.
32
+ *
33
+ * Returned by both {@link exchangePkceCode} and {@link refreshPkceToken} in
34
+ * `@cleocode/core/llm/oauth/pkce.ts`.
35
+ *
36
+ * @task T9302
37
+ */
38
+ export interface OAuthTokens {
39
+ /** Bearer access token. */
40
+ accessToken: string;
41
+ /**
42
+ * Refresh token for obtaining new access tokens without user interaction.
43
+ *
44
+ * Not all providers return a refresh token. When absent, the user must
45
+ * re-authorize when the access token expires.
46
+ */
47
+ refreshToken?: string;
48
+ /** Seconds until `accessToken` expires. `undefined` when not provided. */
49
+ expiresIn?: number;
50
+ /** Token type (virtually always `'bearer'`). */
51
+ tokenType: string;
52
+ }
53
+
54
+ // ---------------------------------------------------------------------------
55
+ // PKCE flow config
56
+ // ---------------------------------------------------------------------------
57
+
58
+ /**
59
+ * Configuration for a RFC 7636 PKCE OAuth flow.
60
+ *
61
+ * All URLs and client credentials are provider-specific. Callers obtain an
62
+ * instance from the builtin registry (e.g., `anthropicProfile.oauth`) or
63
+ * construct one directly for a custom provider.
64
+ *
65
+ * @task T9302
66
+ */
67
+ export interface PkceFlowConfig {
68
+ /** Provider name — used only for logging / error messages. */
69
+ provider: string;
70
+ /** OAuth 2.0 client ID registered with the provider. */
71
+ clientId: string;
72
+ /**
73
+ * Authorization endpoint (RFC 6749 §3.1).
74
+ *
75
+ * The user (or headless code) navigates here to grant consent. When the
76
+ * grant succeeds the provider redirects to `redirectUri` with an
77
+ * authorization `code` and the original `state` parameter.
78
+ */
79
+ authorizationEndpoint: string;
80
+ /**
81
+ * Token endpoint (RFC 6749 §3.2).
82
+ *
83
+ * POSTed to when exchanging the authorization `code` for tokens, and again
84
+ * when refreshing an existing access token.
85
+ */
86
+ tokenEndpoint: string;
87
+ /**
88
+ * Space-separated OAuth scopes to request.
89
+ *
90
+ * @example 'org:create_api_key user:profile user:inference'
91
+ */
92
+ scope?: string;
93
+ /**
94
+ * Redirect URI registered with the provider.
95
+ *
96
+ * For CLI / headless flows this is typically `http://localhost:<port>/callback`
97
+ * or a custom URI scheme handled by the CLI binary.
98
+ *
99
+ * @default 'http://localhost'
100
+ */
101
+ redirectUri?: string;
102
+ /**
103
+ * Additional HTTP headers sent with every token-endpoint request.
104
+ *
105
+ * Used for provider-specific version headers (e.g. Anthropic's
106
+ * `anthropic-beta`).
107
+ */
108
+ extraHeaders?: Readonly<Record<string, string>>;
109
+ }
110
+
111
+ // ---------------------------------------------------------------------------
112
+ // ProviderProfile oauth config shape
113
+ // ---------------------------------------------------------------------------
114
+
115
+ /**
116
+ * OAuth configuration embedded in a {@link ProviderProfile}.
117
+ *
118
+ * Added as an optional field `oauth?` on `ProviderProfile` so the CLI login
119
+ * dispatcher can read the mode and endpoints without importing provider-
120
+ * specific modules.
121
+ *
122
+ * @task T9302
123
+ */
124
+ export interface ProviderOAuthConfig {
125
+ /** OAuth grant mode this provider uses. */
126
+ mode: OAuthMode;
127
+ /** OAuth 2.0 client ID. */
128
+ clientId: string;
129
+ /**
130
+ * Authorization endpoint URL (required for `pkce` mode; omit for
131
+ * `device-code`).
132
+ */
133
+ authorizationEndpoint?: string;
134
+ /** Token endpoint URL. */
135
+ tokenEndpoint: string;
136
+ /** Space-separated OAuth scopes. */
137
+ scope?: string;
138
+ /**
139
+ * Redirect URI (required for `pkce` mode; omit for `device-code`).
140
+ *
141
+ * @default 'http://localhost'
142
+ */
143
+ redirectUri?: string;
144
+ }
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Plugin LLM access types for the CLEO trust-gating layer.
3
+ *
4
+ * Defines the context, completion signature, and error types that the plugin
5
+ * LLM facade exposes to plugin consumers. Sandboxing (filesystem/network
6
+ * isolation) is deferred to Phase 5 (T9313). This module covers model-gating
7
+ * and credential-redaction concerns only.
8
+ *
9
+ * @module llm/plugin-llm
10
+ * @task T9305
11
+ * @epic T9261 T-LLM-CRED-CENTRALIZATION
12
+ * @see ADR-072 §6 plugin facade
13
+ */
14
+
15
+ import type { SendOptions } from './interfaces.js';
16
+ import type { NormalizedResponse, TransportMessage } from './normalized-response.js';
17
+
18
+ // ---------------------------------------------------------------------------
19
+ // Plugin context
20
+ // ---------------------------------------------------------------------------
21
+
22
+ /**
23
+ * Context describing a plugin's identity and LLM access constraints.
24
+ *
25
+ * `allowedModels` and `allowedProviders` are additive allow-lists. When both
26
+ * are supplied the request must satisfy BOTH. When a list is omitted (or
27
+ * empty) that axis is unconstrained.
28
+ */
29
+ export interface PluginLlmContext {
30
+ /** Unique plugin identifier registered in the plugin manifest. */
31
+ readonly pluginId: string;
32
+ /**
33
+ * Optional list of model identifiers the plugin is permitted to call.
34
+ *
35
+ * Values are matched against the `model` field on the resolved role config.
36
+ * When omitted or empty any model is allowed.
37
+ */
38
+ readonly allowedModels?: readonly string[];
39
+ /**
40
+ * Optional list of provider identifiers the plugin is permitted to use.
41
+ *
42
+ * Values are matched against the `ModelTransport` union members
43
+ * (e.g. `'anthropic'`, `'openai'`). When omitted or empty any provider is
44
+ * allowed.
45
+ */
46
+ readonly allowedProviders?: readonly string[];
47
+ }
48
+
49
+ // ---------------------------------------------------------------------------
50
+ // Completion signature
51
+ // ---------------------------------------------------------------------------
52
+
53
+ /**
54
+ * Single-turn plugin LLM completion function.
55
+ *
56
+ * Implementations MUST:
57
+ * - Validate `ctx.allowedModels` / `ctx.allowedProviders` before dispatching.
58
+ * - Redact credential patterns from errors before re-throwing.
59
+ * - NOT append messages to the underlying session history.
60
+ *
61
+ * @param ctx - Plugin identity and access constraints.
62
+ * @param messages - Conversation messages in provider-neutral form.
63
+ * @param opts - Optional per-call send options forwarded to the executor.
64
+ * @returns A promise resolving to a {@link NormalizedResponse}.
65
+ */
66
+ export type PluginLlmComplete = (
67
+ ctx: PluginLlmContext,
68
+ messages: TransportMessage[],
69
+ opts?: SendOptions,
70
+ ) => Promise<NormalizedResponse>;
71
+
72
+ // ---------------------------------------------------------------------------
73
+ // Error types
74
+ // ---------------------------------------------------------------------------
75
+
76
+ /**
77
+ * Thrown when a plugin requests a model or provider not in its allow-list.
78
+ *
79
+ * Consumers can `instanceof PluginModelGateError` to distinguish trust-gating
80
+ * failures from general executor errors.
81
+ */
82
+ export class PluginModelGateError extends Error {
83
+ /** Plugin that triggered the gate. */
84
+ readonly pluginId: string;
85
+ /** The model or provider identifier that was denied. */
86
+ readonly denied: string;
87
+ /** Which axis triggered the gate: model or provider. */
88
+ readonly axis: 'model' | 'provider';
89
+
90
+ /**
91
+ * @param pluginId - Plugin whose request was denied.
92
+ * @param denied - The specific value that was not in the allow-list.
93
+ * @param axis - Whether the denial was on the `model` or `provider` axis.
94
+ */
95
+ constructor(pluginId: string, denied: string, axis: 'model' | 'provider') {
96
+ super(
97
+ `Plugin "${pluginId}" is not permitted to use ${axis} "${denied}". ` +
98
+ `Check the plugin manifest's allowed${axis === 'model' ? 'Models' : 'Providers'} list.`,
99
+ );
100
+ this.name = 'PluginModelGateError';
101
+ this.pluginId = pluginId;
102
+ this.denied = denied;
103
+ this.axis = axis;
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Wraps an underlying executor error after credential patterns have been
109
+ * redacted from its message and stack.
110
+ *
111
+ * The original cause is preserved in `Error.cause` for internal logging but
112
+ * the message and stack exposed to the plugin are sanitised.
113
+ */
114
+ export class PluginLlmError extends Error {
115
+ /** Plugin on whose behalf the call was made. */
116
+ readonly pluginId: string;
117
+
118
+ /**
119
+ * @param pluginId - Plugin on whose behalf the failing call was made.
120
+ * @param redactedMessage - Credential-scrubbed error message.
121
+ * @param cause - Original unscrubbed error (for internal diagnostics).
122
+ */
123
+ constructor(pluginId: string, redactedMessage: string, cause: unknown) {
124
+ super(redactedMessage, { cause });
125
+ this.name = 'PluginLlmError';
126
+ this.pluginId = pluginId;
127
+ }
128
+ }
@@ -12,6 +12,7 @@
12
12
 
13
13
  import type { ModelTransport, StoredAuthTypeWire } from '../operations/llm.js';
14
14
  import type { TransportMessage, TransportTool } from './normalized-response.js';
15
+ import type { ProviderOAuthConfig } from './oauth.js';
15
16
 
16
17
  /**
17
18
  * Describes a single LLM provider — its auth capabilities, base URL,
@@ -162,6 +163,19 @@ export interface ProviderProfile {
162
163
  * @default false
163
164
  */
164
165
  readonly supportsThinkingBudget?: boolean;
166
+
167
+ /**
168
+ * OAuth configuration for this provider.
169
+ *
170
+ * When present, `cleo llm login <provider>` dispatches to the specified
171
+ * OAuth flow rather than requiring a manual API key. The `mode` field
172
+ * selects the grant type:
173
+ * - `pkce` — RFC 7636 Authorization Code + PKCE (browser or headless).
174
+ * - `device-code` — RFC 8628 Device Authorization Grant (polling).
175
+ *
176
+ * @task T9302
177
+ */
178
+ readonly oauth?: ProviderOAuthConfig;
165
179
  }
166
180
 
167
181
  /**
@@ -0,0 +1,78 @@
1
+ /**
2
+ * ContextEngine interface contract — canonical location.
3
+ *
4
+ * Defines the compression contract used by {@link LlmExecutor} to keep
5
+ * session history within the model's context budget. An engine is injected
6
+ * at executor construction time; when absent the executor silently skips
7
+ * all compression checks.
8
+ *
9
+ * @module memory/context-engine
10
+ * @task T9304
11
+ * @epic T9261 T-LLM-CRED-CENTRALIZATION
12
+ * @see ADR-072 §"LlmExecutor — agent-loop level"
13
+ */
14
+
15
+ import type { TransportMessage } from '../llm/normalized-response.js';
16
+
17
+ // ---------------------------------------------------------------------------
18
+ // CompressedContext
19
+ // ---------------------------------------------------------------------------
20
+
21
+ /**
22
+ * Result returned by {@link ContextEngine.compress}.
23
+ *
24
+ * Carries the compressed message array alongside before/after token counts so
25
+ * the executor can emit a `context_compressed` event with accurate metrics.
26
+ */
27
+ export interface CompressedContext {
28
+ /** The compressed message array that replaces the original history. */
29
+ readonly compressedMessages: TransportMessage[];
30
+ /** Estimated token count of the original history before compression. */
31
+ readonly beforeTokens: number;
32
+ /** Estimated token count of the compressed history after compression. */
33
+ readonly afterTokens: number;
34
+ }
35
+
36
+ // ---------------------------------------------------------------------------
37
+ // ContextEngine
38
+ // ---------------------------------------------------------------------------
39
+
40
+ /**
41
+ * Optional context-compression engine supplied to {@link LlmExecutor}.
42
+ *
43
+ * When present, the executor calls {@link shouldCompress} before each model
44
+ * turn. If it returns `true`, the executor calls {@link compress} to reduce
45
+ * the session history, replaces it with {@link CompressedContext.compressedMessages},
46
+ * then emits a `context_compressed` event with the before/after token counts.
47
+ *
48
+ * When absent (undefined), the executor skips all compression checks silently.
49
+ *
50
+ * @see ADR-072 §"LlmExecutor — agent-loop level"
51
+ */
52
+ export interface ContextEngine {
53
+ /**
54
+ * Returns `true` when the current prompt size warrants compression.
55
+ *
56
+ * The executor passes the estimated prompt token count and the model's
57
+ * effective context budget so the engine can apply a threshold ratio
58
+ * (e.g. compress when `promptTokens / contextBudget >= 0.75`).
59
+ *
60
+ * @param promptTokens - Estimated token count of the current session history.
61
+ * @param contextBudget - Effective context-window budget for the bound model.
62
+ * @returns Whether compression should be applied before the next model turn.
63
+ */
64
+ shouldCompress(promptTokens: number, contextBudget: number): boolean;
65
+
66
+ /**
67
+ * Compresses the session history and returns the result.
68
+ *
69
+ * Implementations SHOULD preserve the first few and last few messages
70
+ * verbatim to maintain context anchoring, and summarize the middle window
71
+ * via an auxiliary LLM call.
72
+ *
73
+ * @param messages - Current read-only conversation history snapshot.
74
+ * @param focusTopic - Optional topic hint to guide summarization focus.
75
+ * @returns Promise resolving to the compressed context with token metrics.
76
+ */
77
+ compress(messages: readonly TransportMessage[], focusTopic?: string): Promise<CompressedContext>;
78
+ }
@@ -206,15 +206,13 @@ export interface CredentialResultWire {
206
206
  * Resolution chain order:
207
207
  * 1. `role` — `config.llm.roles[role]` (explicit override)
208
208
  * 2. `default` — `config.llm.default` (canonical default)
209
- * 3. `daemon-legacy` `config.llm.daemon` (deprecated alias)
210
- * 4. `implicit-fallback` — hard-coded fallback inside the resolver
209
+ * 3. `implicit-fallback` hard-coded fallback inside the resolver
211
210
  *
212
- * Useful for `cleo llm whoami` diagnostics and for migration tooling that
213
- * needs to identify call-sites still on the legacy `daemon` block.
211
+ * Useful for `cleo llm whoami` diagnostics.
214
212
  *
215
- * @task T9255
213
+ * @task T9306
216
214
  */
217
- export type ResolutionSource = 'role' | 'default' | 'daemon-legacy' | 'implicit-fallback';
215
+ export type ResolutionSource = 'role' | 'default' | 'implicit-fallback';
218
216
 
219
217
  /**
220
218
  * Result envelope returned by `resolveLLMForRole(role)`.
@@ -568,3 +566,49 @@ export interface LlmWhoamiResult {
568
566
  // The generated catalog (packages/core/src/llm/generated/provider-profiles.ts)
569
567
  // imports the canonical type from the contracts package and emits each
570
568
  // generated entry as a plain ProviderProfile literal.
569
+
570
+ // ---------------------------------------------------------------------------
571
+ // llm-status types (T9323)
572
+ // ---------------------------------------------------------------------------
573
+
574
+ /**
575
+ * Resolved credential source for a single LLM provider.
576
+ *
577
+ * Mirrors the subset of `CredentialSource` relevant for human-facing status
578
+ * output. `'none'` means no credential was found at any tier.
579
+ *
580
+ * @task T9323
581
+ */
582
+ export type LlmProviderSourceWire = 'env' | 'cred-file' | 'claude-creds' | 'config' | 'none';
583
+
584
+ /**
585
+ * Per-provider status entry emitted by `cleo memory llm-status`.
586
+ *
587
+ * @task T9323
588
+ */
589
+ export interface LlmProviderStatusEntry {
590
+ /** Provider identifier (e.g. `'anthropic'`, `'kimi-code'`). */
591
+ provider: string;
592
+ /** Which credential tier resolved the key, or `'none'` if unavailable. */
593
+ resolvedSource: LlmProviderSourceWire;
594
+ /** `true` when a usable credential was found. */
595
+ hasCredential: boolean;
596
+ }
597
+
598
+ /**
599
+ * Result envelope for `memory.llm-status` (query).
600
+ *
601
+ * @task T9323
602
+ */
603
+ export interface LlmStatusResult {
604
+ /** Legacy anthropic-only resolved source (kept for backward compat). */
605
+ resolvedSource: string;
606
+ /** `true` when an Anthropic credential is available (legacy compat field). */
607
+ extractionEnabled: boolean;
608
+ /** ISO timestamp of the most recent extraction run, or `null`. */
609
+ lastExtractionRun: string | null;
610
+ /** Suggested test command. */
611
+ testCommand: string;
612
+ /** Per-provider status for all known OAuth providers. */
613
+ providers: LlmProviderStatusEntry[];
614
+ }