@cleocode/contracts 2026.5.67 → 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 (54) 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 +8 -2
  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 -0
  20. package/dist/llm/interfaces.d.ts.map +1 -1
  21. package/dist/llm/normalized-response.d.ts +10 -0
  22. package/dist/llm/normalized-response.d.ts.map +1 -1
  23. package/dist/llm/oauth.d.ts +125 -0
  24. package/dist/llm/oauth.d.ts.map +1 -0
  25. package/dist/llm/oauth.js +12 -0
  26. package/dist/llm/oauth.js.map +1 -0
  27. package/dist/llm/plugin-llm.d.ts +93 -0
  28. package/dist/llm/plugin-llm.d.ts.map +1 -0
  29. package/dist/llm/plugin-llm.js +65 -0
  30. package/dist/llm/plugin-llm.js.map +1 -0
  31. package/dist/llm/provider-profile.d.ts +23 -0
  32. package/dist/llm/provider-profile.d.ts.map +1 -1
  33. package/dist/memory/context-engine.d.ts +67 -0
  34. package/dist/memory/context-engine.d.ts.map +1 -0
  35. package/dist/memory/context-engine.js +15 -0
  36. package/dist/memory/context-engine.js.map +1 -0
  37. package/dist/operations/llm.d.ts +43 -6
  38. package/dist/operations/llm.d.ts.map +1 -1
  39. package/dist/operations/llm.js +0 -4
  40. package/dist/operations/llm.js.map +1 -1
  41. package/package.json +10 -2
  42. package/src/__tests__/credentials.test.ts +122 -0
  43. package/src/__tests__/llm-config-schema.test.ts +9 -13
  44. package/src/config.ts +37 -55
  45. package/src/credentials.ts +114 -0
  46. package/src/index.ts +22 -7
  47. package/src/llm/failover-reason.ts +1 -1
  48. package/src/llm/interfaces.ts +13 -0
  49. package/src/llm/normalized-response.ts +10 -0
  50. package/src/llm/oauth.ts +144 -0
  51. package/src/llm/plugin-llm.ts +128 -0
  52. package/src/llm/provider-profile.ts +25 -0
  53. package/src/memory/context-engine.ts +78 -0
  54. 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,
@@ -446,11 +451,11 @@ export type {
446
451
  TransportContext,
447
452
  } from './llm/interfaces.js';
448
453
  // === Normalized LLM Transport Types (T9263 — Phase 3 T-LLM-CRED) ===
449
- // Note: LlmTransport (the interface) is intentionally NOT re-exported at the
450
- // top level here because `config.ts` already exports `LlmTransport` as a type
451
- // alias for `ModelTransport`. Consumers that need the transport interface
452
- // should import the LlmTransport interface from the llm/normalized-response.js
453
- // 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.
454
459
  export type {
455
460
  NormalizedResponse,
456
461
  NormalizedToolCall,
@@ -459,6 +464,11 @@ export type {
459
464
  TransportRequest,
460
465
  TransportTool,
461
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';
462
472
  // === Phase 4 Unified Architecture (T9281 / ADR-072) — Provider identity ===
463
473
  export type { ApiMode, BuiltinProviderId, ProviderId } from './llm/provider-id.js';
464
474
  // === Provider Profile + Plugin Contracts (T9262 — Phase 3 T-LLM-CRED) ===
@@ -469,6 +479,8 @@ export type {
469
479
  } from './llm/provider-profile.js';
470
480
  // === Phase 4 Unified Architecture (T9281 / ADR-072) — Resolved credential ===
471
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';
472
484
  export type {
473
485
  BridgeDecision,
474
486
  BridgeLearning,
@@ -674,8 +686,11 @@ export type {
674
686
  LlmListResult,
675
687
  LlmProfileParams,
676
688
  LlmProfileResult,
689
+ LlmProviderSourceWire,
690
+ LlmProviderStatusEntry,
677
691
  LlmRemoveParams,
678
692
  LlmRemoveResult,
693
+ LlmStatusResult,
679
694
  LlmStoredCredentialView,
680
695
  LlmTestParams,
681
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 };
@@ -390,6 +396,13 @@ export interface ExecutionRequest {
390
396
  readonly sendOptions?: SendOptions;
391
397
  }
392
398
 
399
+ // ---------------------------------------------------------------------------
400
+ // Context engine (canonical definition: packages/contracts/src/memory/context-engine.ts)
401
+ // ---------------------------------------------------------------------------
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.
405
+
393
406
  // ---------------------------------------------------------------------------
394
407
  // Executor interface
395
408
  // ---------------------------------------------------------------------------
@@ -245,6 +245,16 @@ export interface TransportRequest {
245
245
  * @see ADR-072 §LlmTransport — pure wire level
246
246
  */
247
247
  readonly imageMode?: 'native' | 'text' | 'auto';
248
+ /**
249
+ * Anthropic-style extended thinking budget (token count).
250
+ *
251
+ * Providers that do NOT support thinking budgets (e.g. Moonshot) MUST
252
+ * reject this field with an error. Transports validate this against the
253
+ * provider profile before constructing the SDK request.
254
+ *
255
+ * @task T9286 (W1d — Moonshot thinkingBudgetTokens rejection)
256
+ */
257
+ readonly thinkingBudgetTokens?: number | null;
248
258
  }
249
259
 
250
260
  /**
@@ -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,
@@ -151,6 +152,30 @@ export interface ProviderProfile {
151
152
  messages: readonly TransportMessage[],
152
153
  tools: readonly TransportTool[],
153
154
  ) => Readonly<Record<string, unknown>>;
155
+
156
+ /**
157
+ * Whether this provider supports Anthropic-style extended thinking budget
158
+ * tokens (`thinkingBudgetTokens` on the transport request).
159
+ *
160
+ * When `false` (or absent), the transport MUST throw if a caller sets
161
+ * `thinkingBudgetTokens` on the request — the provider's API will reject it.
162
+ *
163
+ * @default false
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;
154
179
  }
155
180
 
156
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
+ }