@gajae-code/coding-agent 0.12.21 → 0.13.0

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 (222) hide show
  1. package/CHANGELOG.md +67 -2
  2. package/dist/types/cli/args.d.ts +5 -2
  3. package/dist/types/cli/root-flags.d.ts +246 -0
  4. package/dist/types/cli.d.ts +11 -19
  5. package/dist/types/commands/daemon.d.ts +0 -30
  6. package/dist/types/commands/launch.d.ts +11 -19
  7. package/dist/types/commands/quick-lane.d.ts +32 -0
  8. package/dist/types/commands/sdk.d.ts +21 -15
  9. package/dist/types/config/file-lock-gc.d.ts +2 -0
  10. package/dist/types/config/model-equivalence.d.ts +20 -0
  11. package/dist/types/config/model-profile-activation.d.ts +62 -17
  12. package/dist/types/config/model-profiles.d.ts +10 -0
  13. package/dist/types/config/model-registry.d.ts +68 -1
  14. package/dist/types/config/model-resolver.d.ts +15 -4
  15. package/dist/types/config/models-config-schema.d.ts +7 -2
  16. package/dist/types/config/provider-selection-policy.d.ts +62 -0
  17. package/dist/types/config/settings-schema.d.ts +36 -78
  18. package/dist/types/config/settings.d.ts +2 -0
  19. package/dist/types/edit/renderer.d.ts +5 -2
  20. package/dist/types/edit/streaming.d.ts +13 -0
  21. package/dist/types/extensibility/custom-tools/types.d.ts +2 -0
  22. package/dist/types/extensibility/extensions/compact-handler.d.ts +2 -1
  23. package/dist/types/extensibility/extensions/types.d.ts +3 -0
  24. package/dist/types/gjc-runtime/gc-runtime.d.ts +19 -5
  25. package/dist/types/internal-urls/local-protocol.d.ts +1 -0
  26. package/dist/types/modes/components/model-selector.d.ts +0 -2
  27. package/dist/types/modes/components/provider-order-context.d.ts +45 -0
  28. package/dist/types/modes/components/provider-order-editor.d.ts +24 -0
  29. package/dist/types/modes/components/settings-defs.d.ts +5 -1
  30. package/dist/types/modes/components/settings-selector.d.ts +2 -0
  31. package/dist/types/quick-lane/classify.d.ts +40 -0
  32. package/dist/types/runtime/stt-settings-setup.d.ts +18 -0
  33. package/dist/types/sdk/broker/broker.d.ts +56 -2
  34. package/dist/types/sdk/broker/operation-receipt-ledger.d.ts +25 -0
  35. package/dist/types/sdk/broker/session-index.d.ts +83 -2
  36. package/dist/types/sdk/broker/state-version.d.ts +1 -1
  37. package/dist/types/sdk/bus/notification-service.d.ts +6 -0
  38. package/dist/types/sdk/bus/prompt-reconciliation.d.ts +8 -1
  39. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +4 -1
  40. package/dist/types/sdk/bus/telegram-daemon.d.ts +26 -0
  41. package/dist/types/sdk/cli/rows.d.ts +98 -0
  42. package/dist/types/sdk/cli/session-cli.d.ts +35 -3
  43. package/dist/types/sdk/elevation/allowlist.d.ts +20 -0
  44. package/dist/types/sdk/elevation/audit.d.ts +93 -0
  45. package/dist/types/sdk/elevation/capability.d.ts +3 -0
  46. package/dist/types/sdk/elevation/digest.d.ts +72 -0
  47. package/dist/types/sdk/elevation/dispatch-receipt.d.ts +85 -0
  48. package/dist/types/sdk/elevation/grant-ledger.d.ts +163 -0
  49. package/dist/types/sdk/elevation/owner.d.ts +48 -0
  50. package/dist/types/sdk/guides/cache.d.ts +98 -0
  51. package/dist/types/sdk/guides/catalog.d.ts +156 -0
  52. package/dist/types/sdk/guides/cli.d.ts +39 -0
  53. package/dist/types/sdk/guides/manifest.d.ts +66 -0
  54. package/dist/types/sdk/guides/verify.d.ts +66 -0
  55. package/dist/types/sdk/host/control/dispatch.d.ts +8 -0
  56. package/dist/types/sdk/host/control/index.d.ts +1 -1
  57. package/dist/types/sdk/host/control/operations.d.ts +3 -2
  58. package/dist/types/sdk/host/query/cursor.d.ts +10 -0
  59. package/dist/types/sdk/host/query/handlers.d.ts +21 -0
  60. package/dist/types/sdk/host/session-runtime.d.ts +9 -0
  61. package/dist/types/sdk/mcp/server.d.ts +2 -2
  62. package/dist/types/sdk/prompt-status.d.ts +11 -0
  63. package/dist/types/sdk/session.d.ts +4 -0
  64. package/dist/types/sdk/transport/index.d.ts +1 -0
  65. package/dist/types/sdk/transport/relay.d.ts +1 -0
  66. package/dist/types/sdk/transport/serve-cli.d.ts +20 -1
  67. package/dist/types/session/agent-session.d.ts +32 -18
  68. package/dist/types/session/blob-store.d.ts +13 -7
  69. package/dist/types/session/fallback-chain-controller.d.ts +15 -0
  70. package/dist/types/session/internal/managed-session-storage.d.ts +25 -1
  71. package/dist/types/session/internal/session-memory-sidecar.d.ts +5 -5
  72. package/dist/types/session/session-manager.d.ts +139 -10
  73. package/dist/types/session/session-storage.d.ts +48 -0
  74. package/dist/types/setup/provider-onboarding.d.ts +7 -1
  75. package/dist/types/slash-commands/builtin-registry.d.ts +14 -0
  76. package/dist/types/stt/setup.d.ts +2 -0
  77. package/dist/types/task/executor.d.ts +10 -2
  78. package/dist/types/tools/browser/runtime-diagnostics.d.ts +65 -0
  79. package/dist/types/tools/browser/tab-protocol.d.ts +4 -0
  80. package/dist/types/tools/browser/tab-supervisor.d.ts +2 -0
  81. package/dist/types/tools/browser/tab-worker.d.ts +2 -0
  82. package/dist/types/tools/browser.d.ts +2 -0
  83. package/dist/types/tools/image-gen.d.ts +14 -18
  84. package/dist/types/tools/index.d.ts +2 -0
  85. package/dist/types/tools/resource-gc.d.ts +2 -0
  86. package/dist/types/utils/pasted-image-path.d.ts +6 -0
  87. package/package.json +9 -9
  88. package/scripts/generate-sdk-operation-inventory.ts +8 -0
  89. package/scripts/run-test-manifest.ts +61 -21
  90. package/scripts/verify-gjc-sdk-canonicalization.ts +9 -4
  91. package/src/cli/args.ts +62 -9
  92. package/src/cli/completion-cli.ts +1 -0
  93. package/src/cli/fast-help.ts +1 -0
  94. package/src/cli/root-flags.ts +100 -0
  95. package/src/cli/setup-cli.ts +6 -2
  96. package/src/cli.ts +42 -65
  97. package/src/commands/acp.ts +1 -1
  98. package/src/commands/daemon.ts +2 -31
  99. package/src/commands/gc.ts +1 -1
  100. package/src/commands/launch.ts +8 -129
  101. package/src/commands/quick-lane.ts +51 -0
  102. package/src/commands/sdk.ts +200 -26
  103. package/src/commands/setup.ts +4 -2
  104. package/src/config/file-lock-gc.ts +4 -1
  105. package/src/config/model-equivalence.ts +76 -7
  106. package/src/config/model-profile-activation.ts +1115 -265
  107. package/src/config/model-profiles.ts +134 -2
  108. package/src/config/model-registry.ts +352 -50
  109. package/src/config/model-resolver.ts +289 -38
  110. package/src/config/models-config-schema.ts +11 -4
  111. package/src/config/provider-selection-policy.ts +146 -0
  112. package/src/config/settings-schema.ts +50 -77
  113. package/src/config/settings.ts +40 -0
  114. package/src/coordinator-mcp/server.ts +32 -2
  115. package/src/edit/renderer.ts +175 -223
  116. package/src/edit/streaming.ts +108 -1
  117. package/src/export/html/index.ts +57 -7
  118. package/src/extensibility/custom-tools/types.ts +2 -0
  119. package/src/extensibility/extensions/compact-handler.ts +3 -2
  120. package/src/extensibility/extensions/runner.ts +6 -0
  121. package/src/extensibility/extensions/types.ts +3 -0
  122. package/src/gjc-runtime/gc-runtime.ts +379 -20
  123. package/src/gjc-runtime/launch-worktree.ts +5 -1
  124. package/src/gjc-runtime/team-runtime.ts +59 -2
  125. package/src/gjc-runtime/tmux-owner-isolation.ts +19 -0
  126. package/src/gjc-runtime/ultragoal-receipt-freshness.ts +16 -1
  127. package/src/internal-urls/docs-index.generated.ts +17 -13
  128. package/src/internal-urls/local-protocol.ts +1 -0
  129. package/src/main.ts +40 -3
  130. package/src/memories/index.ts +4 -2
  131. package/src/modes/acp/acp-agent.ts +235 -91
  132. package/src/modes/components/model-selector.ts +206 -42
  133. package/src/modes/components/provider-order-context.ts +197 -0
  134. package/src/modes/components/provider-order-editor.ts +441 -0
  135. package/src/modes/components/settings-defs.ts +21 -1
  136. package/src/modes/components/settings-selector.ts +45 -2
  137. package/src/modes/components/tool-execution.ts +47 -15
  138. package/src/modes/controllers/command-controller.ts +6 -3
  139. package/src/modes/controllers/extension-ui-controller.ts +2 -0
  140. package/src/modes/controllers/input-controller.ts +73 -2
  141. package/src/modes/controllers/selector-controller.ts +260 -153
  142. package/src/modes/prompt-suggestion-controller.ts +1 -1
  143. package/src/modes/runtime-init.ts +1 -0
  144. package/src/modes/utils/ui-helpers.ts +18 -0
  145. package/src/prompts/tools/browser.md +1 -0
  146. package/src/quick-lane/classify.ts +257 -0
  147. package/src/rlm/index.ts +1 -1
  148. package/src/runtime/stt-settings-setup.ts +57 -0
  149. package/src/sdk/acp/adapter.ts +2 -1
  150. package/src/sdk/broker/broker.ts +780 -12
  151. package/src/sdk/broker/lifecycle.ts +70 -29
  152. package/src/sdk/broker/operation-receipt-ledger.ts +144 -0
  153. package/src/sdk/broker/session-index.ts +463 -48
  154. package/src/sdk/broker/state-version.ts +13 -9
  155. package/src/sdk/broker/transport.ts +14 -1
  156. package/src/sdk/bus/index.ts +34 -13
  157. package/src/sdk/bus/kind-aware-reconciliation.ts +21 -2
  158. package/src/sdk/bus/notification-service.ts +47 -1
  159. package/src/sdk/bus/prompt-reconciliation.ts +22 -3
  160. package/src/sdk/bus/telegram-daemon-contract.ts +4 -1
  161. package/src/sdk/bus/telegram-daemon.ts +54 -3
  162. package/src/sdk/cli/rows.ts +247 -0
  163. package/src/sdk/cli/session-cli.ts +930 -79
  164. package/src/sdk/elevation/allowlist.ts +54 -0
  165. package/src/sdk/elevation/audit.ts +208 -0
  166. package/src/sdk/elevation/capability.ts +41 -0
  167. package/src/sdk/elevation/digest.ts +129 -0
  168. package/src/sdk/elevation/dispatch-receipt.ts +184 -0
  169. package/src/sdk/elevation/grant-ledger.ts +1142 -0
  170. package/src/sdk/elevation/owner.ts +109 -0
  171. package/src/sdk/guides/cache.ts +363 -0
  172. package/src/sdk/guides/catalog.ts +554 -0
  173. package/src/sdk/guides/cli.ts +235 -0
  174. package/src/sdk/guides/manifest.ts +152 -0
  175. package/src/sdk/guides/verify.ts +178 -0
  176. package/src/sdk/host/control/dispatch.ts +49 -1
  177. package/src/sdk/host/control/index.ts +1 -0
  178. package/src/sdk/host/control/operations.ts +8 -1
  179. package/src/sdk/host/query/cursor.ts +47 -3
  180. package/src/sdk/host/query/handlers.ts +155 -2
  181. package/src/sdk/host/sdk-surface-parity.test.ts +1 -0
  182. package/src/sdk/host/session-runtime.test.ts +391 -1
  183. package/src/sdk/host/session-runtime.ts +308 -73
  184. package/src/sdk/host/surface-policy.ts +3 -0
  185. package/src/sdk/host/websocket-transport.ts +7 -1
  186. package/src/sdk/mcp/server.ts +88 -15
  187. package/src/sdk/prompt-status.ts +8 -0
  188. package/src/sdk/protocol/operation-inventory.generated.json +62 -0
  189. package/src/sdk/protocol/operation-registry.ts +3 -2
  190. package/src/sdk/session.ts +87 -39
  191. package/src/sdk/transport/index.ts +1 -0
  192. package/src/sdk/transport/relay.ts +3 -0
  193. package/src/sdk/transport/serve-cli.ts +111 -24
  194. package/src/secrets/obfuscator.ts +92 -12
  195. package/src/session/agent-session.ts +322 -93
  196. package/src/session/blob-store.ts +60 -8
  197. package/src/session/fallback-chain-controller.ts +35 -0
  198. package/src/session/internal/managed-session-scope.ts +25 -3
  199. package/src/session/internal/managed-session-storage.ts +574 -73
  200. package/src/session/internal/session-memory-sidecar.ts +19 -29
  201. package/src/session/session-manager.ts +2166 -743
  202. package/src/session/session-storage.ts +715 -48
  203. package/src/setup/provider-onboarding.ts +19 -3
  204. package/src/setup/provider-presets.json +3 -1
  205. package/src/slash-commands/builtin-registry.ts +85 -3
  206. package/src/stt/downloader.ts +2 -3
  207. package/src/stt/setup.ts +29 -4
  208. package/src/task/executor.ts +22 -18
  209. package/src/task/index.ts +24 -1
  210. package/src/tools/archive-reader.ts +11 -2
  211. package/src/tools/browser/runtime-diagnostics.ts +249 -0
  212. package/src/tools/browser/tab-protocol.ts +4 -0
  213. package/src/tools/browser/tab-supervisor.ts +5 -0
  214. package/src/tools/browser/tab-worker.ts +36 -1
  215. package/src/tools/browser.ts +7 -0
  216. package/src/tools/image-gen.ts +110 -166
  217. package/src/tools/index.ts +2 -0
  218. package/src/tools/read.ts +1 -1
  219. package/src/tools/resource-gc.ts +6 -1
  220. package/src/tools/tool-catalog.generated.ts +5 -1
  221. package/src/utils/pasted-image-path.ts +93 -0
  222. package/src/web/search/index.ts +3 -3
@@ -52,25 +52,31 @@ export declare const SESSION_HOST_DETACHED_IDLE_GRACE_MS: number;
52
52
  */
53
53
  export declare const SESSION_HOST_FIRST_ATTACH_GRACE_MS: number;
54
54
  /**
55
- * Resolves once this host is provably abandoned: either it has been detached
56
- * from every client for the full idle grace, or nobody has come for it at all
57
- * for the full first-attach grace.
55
+ * Resolves once the host is provably abandoned: either it has been detached
56
+ * from every client for a full idle grace, or nobody has come for it at all
57
+ * for a full first-attach grace.
58
58
  *
59
59
  * `readAttachedClients` reports the host's own live client/socket subscription
60
- * count; `undefined` means the SDK endpoint publishes no such evidence yet and
61
- * is deliberately *not* treated as detachment, so a host can never be reaped on
62
- * missing evidence — only on observed absence of clients.
60
+ * count; `undefined` means the SDK endpoint publishes no such evidence — before
61
+ * startup, after teardown, or when every reader itself fails. That ambiguity is
62
+ * never instant detachment: it cannot reap on the poll that first sees it, it
63
+ * can only open a window. Which window depends on what was already observed. A
64
+ * host never seen attached accrues against the first-attach bound. A host that
65
+ * was seen attached and has since lost its evidence is in the *more* suspicious
66
+ * state — a runtime that retracted its registration during teardown looks
67
+ * exactly like this — so it accrues against the detached idle bound, alongside
68
+ * an observed count of zero. Every reachable state therefore carries a finite
69
+ * bound.
63
70
  *
64
71
  * `readWorkInFlight` reports whether the host is running agent work right now.
65
- * Work is positive proof that a client did come for this host: a prompt can
66
- * only arrive over the endpoint a client dialed. So for a host that has never
67
- * been *observed* attached — a client that connected, prompted and dropped
68
- * between two 30s polls, or a client count that is momentarily unreadable — the
69
- * first-attach window is measured from the last moment work was in flight
70
- * rather than from process start. That still bounds a host whose SDK runtime
71
- * never came up: with no transport it can never receive a prompt, so it never
72
- * reports work and its window keeps running from start. And any real turn ends,
73
- * after which the window resumes; live work defers the bound, never removes it.
72
+ * Work is positive proof a client did come for this host: a prompt can only
73
+ * arrive over an endpoint a client dialed. Live work therefore restarts both
74
+ * windows, which is what keeps a mid-prompt host alive whether its count reads
75
+ * zero or stops being readable at all. That still bounds a host whose SDK
76
+ * runtime never came up: with no transport it can never receive a prompt, so it
77
+ * never reports work and its window keeps running from process start. And any
78
+ * real turn ends, after which the window resumes; live work defers a bound, it
79
+ * never removes it.
74
80
  */
75
81
  export declare function watchSessionHostClientAttachment(deps: {
76
82
  readAttachedClients: () => number | undefined;
@@ -7,6 +7,8 @@ export declare const FILE_LOCK_GC_MAX_WALK_ENTRIES = 20000;
7
7
  export interface FileLocksGcCollectOptions {
8
8
  /** Override per-root entry budget (tests). Defaults to {@link FILE_LOCK_GC_MAX_WALK_ENTRIES}. */
9
9
  maxWalkEntries?: number;
10
+ /** Override global lock roots for isolated collection tests. */
11
+ roots?: readonly string[];
10
12
  }
11
13
  /**
12
14
  * Discover + classify file-lock records. Each known lock root gets its own walk
@@ -19,8 +19,23 @@ export interface CanonicalModelIndex {
19
19
  records: CanonicalModelRecord[];
20
20
  byId: Map<string, CanonicalModelRecord>;
21
21
  bySelector: Map<string, string>;
22
+ /**
23
+ * Final-slash-segment lookup aliases: normalized alias key -> normalized
24
+ * variant selectors ("provider/id") of every variant whose model id ends in
25
+ * that segment. Variant-level: an alias never widens to sibling variants in
26
+ * the same canonical record that end in a different segment. Multi-target
27
+ * when distinct variants collide on the same segment. Built without
28
+ * rewriting the canonical or runtime identity of any variant.
29
+ */
30
+ aliases: Map<string, string[]>;
22
31
  }
23
32
  export declare function formatCanonicalVariantSelector(model: Model<Api>): string;
33
+ /**
34
+ * Normalize a model id into its final-slash-segment alias key (trimmed and
35
+ * lowercased). A bare id without a slash yields the id itself; a multi-level
36
+ * id yields its last path segment. Returns undefined for empty ids.
37
+ */
38
+ export declare function getFinalSlashSegmentAliasKey(modelId: string): string | undefined;
24
39
  /**
25
40
  * Compare equivalent provider variants using the caller's ranking policy.
26
41
  *
@@ -29,8 +44,13 @@ export declare function formatCanonicalVariantSelector(model: Model<Api>): strin
29
44
  * source, input plus cache-read cost, and original catalog order. Callers that
30
45
  * do not have a canonical index can omit those axes while retaining a stable,
31
46
  * total comparison.
47
+ *
48
+ * `providerRankFirst` swaps the first two axes so configured provider rank wins
49
+ * over vision support; canonical/alias resolution uses this order while every
50
+ * existing caller keeps the legacy vision-first order by default.
32
51
  */
33
52
  export declare function compareEquivalentModelVariants(left: Model<Api>, right: Model<Api>, options?: {
53
+ providerRankFirst?: boolean;
34
54
  providerRank?: ReadonlyMap<string, number>;
35
55
  canonicalId?: string;
36
56
  leftSourceRank?: number;
@@ -1,11 +1,12 @@
1
1
  import { ThinkingLevel } from "@gajae-code/agent-core";
2
2
  import type { Api, Model } from "@gajae-code/ai/core";
3
- import type { AgentSession } from "../session/agent-session";
3
+ import type { AgentSession, DefaultFallbackRuntimeState } from "../session/agent-session";
4
4
  export { resolveModelProfileName } from "./model-profile-contract";
5
5
  import { type GjcModelAssignmentTargetId, type ModelRegistry } from "./model-registry";
6
6
  import { type ModelSelectorValue } from "./model-selector-value";
7
7
  import type { Settings } from "./settings";
8
8
  type ModelProfileActivationSession = Pick<AgentSession, "model" | "thinkingLevel" | "sessionId" | "getConfiguredModelChain" | "setConfiguredModelChain"> & {
9
+ credentialSessionId?: string;
9
10
  setModelTemporary?: AgentSession["setModelTemporary"];
10
11
  setActiveModelProfile?: (name: string | undefined) => void;
11
12
  getActiveModelProfile?: () => string | undefined;
@@ -19,18 +20,29 @@ type ModelProfileActivationSession = Pick<AgentSession, "model" | "thinkingLevel
19
20
  agentModelOverrides: readonly string[];
20
21
  };
21
22
  getSessionDefaultModelSelector?: () => string | undefined;
22
- recordResumeDefaultModel?: (selector: string) => void;
23
+ recordResumeDefaultModel?: (selector: string | undefined) => void;
23
24
  seedDefaultFallbackResolution?: (activeIndex: number, skips: Array<{
24
25
  selector: string;
25
26
  reason: string;
26
27
  }>) => void;
28
+ getDefaultFallbackRuntimeState?: () => DefaultFallbackRuntimeState;
29
+ restoreDefaultFallbackRuntimeState?: (state: DefaultFallbackRuntimeState) => void;
30
+ restoreModelSelectionForRollback?: AgentSession["restoreModelSelectionForRollback"];
31
+ modelRegistry?: Pick<ModelRegistry, "getSessionCanonicalVariant" | "restoreSessionCanonicalVariant" | "clearCanonicalVariant" | "getAvailable" | "lookupAliasExists" | "resolveModelByLookupAlias" | "authStorage" | "isCredentiallessProvider">;
32
+ getConfiguredModelChainState?: (role: string) => ConfiguredModelChainState | undefined;
33
+ };
34
+ type ConfiguredModelChainState = {
35
+ entries: readonly string[];
36
+ origin: string;
37
+ identity?: string;
38
+ explicitHead: boolean;
27
39
  };
28
40
  export interface PrepareModelProfileActivationOptions {
29
41
  session: ModelProfileActivationSession;
30
- modelRegistry: Pick<ModelRegistry, "getModelProfile" | "getModelProfiles" | "getAvailableModelProfileNames" | "getApiKeyForProvider" | "getAll" | "resolveCanonicalModel" | "getCanonicalVariants" | "getCanonicalId"> & {
42
+ modelRegistry: Pick<ModelRegistry, "getModelProfile" | "getModelProfiles" | "getAvailableModelProfileNames" | "getApiKeyForProvider" | "getAll" | "resolveCanonicalModel" | "getCanonicalVariants" | "getCanonicalId"> & Partial<Pick<ModelRegistry, "getAvailable" | "resolveModelByLookupAlias" | "lookupAliasExists" | "clearCanonicalVariant" | "seedCanonicalVariant" | "getSessionCanonicalVariant" | "restoreSessionCanonicalVariant" | "getConfiguredProviderIds">> & {
31
43
  getError?: ModelRegistry["getError"];
32
44
  };
33
- settings: Pick<Settings, "get" | "getGlobal">;
45
+ settings: Pick<Settings, "get" | "getGlobal" | "getOverride">;
34
46
  profileName: string;
35
47
  }
36
48
  export interface ApplyModelProfileActivationOptions {
@@ -42,14 +54,24 @@ export interface PreparedModelProfileActivation {
42
54
  session: ModelProfileActivationSession & {
43
55
  setModelTemporary: AgentSession["setModelTemporary"];
44
56
  };
45
- settings: Pick<Settings, "clearOverride" | "get" | "getGlobal" | "override" | "set" | "unset" | "flush">;
57
+ settings: Pick<Settings, "clearOverride" | "get" | "getGlobal" | "getOverride" | "override" | "set" | "unset" | "flush" | "flushOrThrow">;
46
58
  previousModel: Model<Api> | undefined;
47
59
  previousThinkingLevel: ThinkingLevel | undefined;
48
60
  previousAgentModelOverrides: Record<string, ModelSelectorValue>;
49
61
  previousModelRoles: Record<string, ModelSelectorValue>;
62
+ previousPersistedModelRoles: Record<string, ModelSelectorValue> | undefined;
63
+ previousPersistedAgentModelOverrides: Record<string, ModelSelectorValue> | undefined;
64
+ previousModelRolesOverride: Record<string, ModelSelectorValue> | undefined;
65
+ previousAgentModelOverridesOverride: Record<string, ModelSelectorValue> | undefined;
66
+ previousDefaultProfileOverride: string | undefined;
67
+ previousPersistedDefaultProfile: string | undefined;
68
+ previousPersistedDefaultThinkingLevel: Exclude<ThinkingLevel, "inherit"> | undefined;
69
+ previousDefaultThinkingLevelOverride: ThinkingLevel | undefined;
50
70
  baseAgentModelOverrides: Record<string, ModelSelectorValue>;
51
71
  baseModelRoles: Record<string, ModelSelectorValue>;
52
72
  previousDefaultChain: readonly string[] | undefined;
73
+ previousDefaultChainState: ConfiguredModelChainState | undefined;
74
+ previousDefaultFallbackRuntimeState: DefaultFallbackRuntimeState | undefined;
53
75
  defaultModel: Model<Api> | undefined;
54
76
  defaultThinkingLevel: ThinkingLevel | undefined;
55
77
  /** Full configured default fallback chain with resolvable entries clamped. */
@@ -72,20 +94,27 @@ export interface PreparedModelProfileActivation {
72
94
  * resume default without promoting a transient model to it.
73
95
  */
74
96
  previousSessionDefaultModel: string | undefined;
97
+ /**
98
+ * Exact concrete sticky selector ("provider/id") snapshotted from the
99
+ * registry BEFORE the session sticky canonical variant is invalidated during
100
+ * prepare. Captured verbatim — never re-derived from the live model — so a
101
+ * transient live-model switch cannot corrupt the restored sticky. Rollback
102
+ * restores this exact selector when present; otherwise the sticky is cleared
103
+ * so a stale provider cannot silently resurrect.
104
+ */
105
+ previousCanonicalVariant: string | undefined;
106
+ /** Registry used to resolve and restore the session sticky canonical variant. */
107
+ modelRegistry: PrepareModelProfileActivationOptions["modelRegistry"];
75
108
  }
76
109
  export interface MaterializeModelProfileAssignmentOptions {
77
- session: Pick<ModelProfileActivationSession, "model" | "thinkingLevel" | "getConfiguredModelChain" | "setActiveModelProfile" | "getActiveModelProfile"> & {
78
- clearProfileInstalledOverrides?: () => void;
79
- };
80
- settings: Pick<Settings, "clearOverride" | "get" | "override" | "set" | "unset">;
110
+ session: Pick<ModelProfileActivationSession, "model" | "thinkingLevel" | "sessionId" | "credentialSessionId" | "getConfiguredModelChain" | "getConfiguredModelChainState" | "setConfiguredModelChain" | "setActiveModelProfile" | "getActiveModelProfile" | "getDefaultFallbackRuntimeState" | "restoreDefaultFallbackRuntimeState" | "modelRegistry" | "clearProfileInstalledOverrides">;
111
+ settings: Pick<Settings, "clearOverride" | "get" | "getGlobal" | "getOverride" | "override" | "set" | "unset">;
81
112
  role: GjcModelAssignmentTargetId;
82
113
  selector: string;
83
114
  }
84
115
  export interface MaterializeModelProfileAssignmentsOptions {
85
- session: Pick<ModelProfileActivationSession, "model" | "thinkingLevel" | "getConfiguredModelChain" | "setActiveModelProfile" | "getActiveModelProfile"> & {
86
- clearProfileInstalledOverrides?: () => void;
87
- };
88
- settings: Pick<Settings, "clearOverride" | "get" | "override" | "set" | "unset">;
116
+ session: Pick<ModelProfileActivationSession, "model" | "thinkingLevel" | "sessionId" | "credentialSessionId" | "getConfiguredModelChain" | "getConfiguredModelChainState" | "setConfiguredModelChain" | "setActiveModelProfile" | "getActiveModelProfile" | "getDefaultFallbackRuntimeState" | "restoreDefaultFallbackRuntimeState" | "modelRegistry" | "clearProfileInstalledOverrides">;
117
+ settings: Pick<Settings, "clearOverride" | "get" | "getGlobal" | "getOverride" | "override" | "set" | "unset">;
89
118
  assignments: ReadonlyMap<GjcModelAssignmentTargetId, string> | Partial<Record<GjcModelAssignmentTargetId, string>>;
90
119
  }
91
120
  export declare function materializeActiveModelProfileAssignment(options: MaterializeModelProfileAssignmentOptions): boolean;
@@ -94,7 +123,8 @@ export declare class ModelProfileCredentialError extends Error {
94
123
  readonly code = "authentication_failed";
95
124
  readonly profileLabel: string;
96
125
  readonly providers: readonly string[];
97
- constructor(profileLabel: string, providers: readonly string[]);
126
+ readonly role: string | undefined;
127
+ constructor(profileLabel: string, providers: readonly string[], role?: string);
98
128
  }
99
129
  export declare function formatModelProfileCredentialError(profileLabel: string, providers: readonly string[]): string;
100
130
  export declare function prepareModelProfileActivation(options: PrepareModelProfileActivationOptions): Promise<PreparedModelProfileActivation>;
@@ -104,16 +134,31 @@ export interface MaterializeModelProfileForDeletionResult {
104
134
  agentModelOverrides: Record<string, ModelSelectorValue>;
105
135
  previousModelRoles: Record<string, ModelSelectorValue>;
106
136
  previousAgentModelOverrides: Record<string, ModelSelectorValue>;
137
+ previousPersistedModelRoles: Record<string, ModelSelectorValue> | undefined;
138
+ previousPersistedAgentModelOverrides: Record<string, ModelSelectorValue> | undefined;
139
+ previousModelRolesOverride: Record<string, ModelSelectorValue> | undefined;
140
+ previousAgentModelOverridesOverride: Record<string, ModelSelectorValue> | undefined;
141
+ previousDefaultProfileOverride: string | undefined;
107
142
  previousDefaultProfile: string | undefined;
108
143
  previousPersistedDefaultProfile: string | undefined;
109
144
  previousActiveModelProfile: string | undefined;
145
+ previousDefaultChainState: ConfiguredModelChainState | undefined;
146
+ previousDefaultFallbackRuntimeState: DefaultFallbackRuntimeState | undefined;
147
+ /**
148
+ * Restores the session sticky canonical variant that was snapshotted before
149
+ * materialization cleared it. Internal closure capturing the registry,
150
+ * session, and exact pre-clear selector — avoids threading a registry
151
+ * through the restore options. Optional so callers that never materialized
152
+ * (or use a registry without sticky support) can still restore settings.
153
+ */
154
+ restoreSessionCanonicalVariant?: () => void;
110
155
  }
111
156
  export declare function materializeModelProfileForDeletion(options: PrepareModelProfileActivationOptions & {
112
- settings: Pick<Settings, "clearOverride" | "flush" | "get" | "getGlobal" | "override" | "set" | "unset">;
157
+ settings: Pick<Settings, "clearOverride" | "flushOrThrow" | "get" | "getGlobal" | "override" | "set" | "unset">;
113
158
  }): Promise<MaterializeModelProfileForDeletionResult>;
114
159
  export declare function restoreMaterializedModelProfileForDeletion(options: {
115
- settings: Pick<Settings, "flush" | "override" | "set">;
116
- session: Pick<ModelProfileActivationSession, "setActiveModelProfile">;
160
+ settings: Pick<Settings, "clearOverride" | "flushOrThrow" | "override" | "set" | "unset">;
161
+ session: Pick<ModelProfileActivationSession, "setActiveModelProfile" | "setConfiguredModelChain" | "restoreDefaultFallbackRuntimeState">;
117
162
  snapshot: MaterializeModelProfileForDeletionResult;
118
163
  }): Promise<void>;
119
164
  export declare function activateModelProfile(options: PrepareModelProfileActivationOptions, applyOptions?: ApplyModelProfileActivationOptions): Promise<void>;
@@ -31,6 +31,16 @@ export declare function deriveModelProfileMappedProviders(definition: Pick<Model
31
31
  */
32
32
  export declare function aggregateModelProfileRequiredProviders(requiredProviders: readonly string[], _definition: Pick<ModelProfileDefinition, "modelMapping">): string[];
33
33
  export declare const BUILTIN_MODEL_PROFILES: readonly ModelProfileDefinition[];
34
+ /**
35
+ * Providers that built-in model presets pin via qualified `<provider>/<model>`
36
+ * selectors. When `modelProfile.proxyProvider` is set, selectors for these
37
+ * providers are rewritten to `<proxy>/<model>` at activation time when their
38
+ * direct provider is unauthenticated, or unconditionally when
39
+ * `modelProfile.proxyMode` is `always`. Bare-alias (open-weights) profiles are
40
+ * not included: they already resolve through any authenticated provider,
41
+ * including a configured proxy.
42
+ */
43
+ export declare const PROXY_ROUTABLE_PROVIDER_IDS: ReadonlySet<string>;
34
44
  export interface ModelProfilePresentation {
35
45
  displayName: string;
36
46
  providerGroup: string;
@@ -12,7 +12,9 @@ export type { ProviderDiscoveryState, ProviderDiscoveryStatus } from "./model-di
12
12
  import { type CanonicalModelIndex, type CanonicalModelRecord, type CanonicalModelVariant, type ModelEquivalenceConfig } from "./model-equivalence";
13
13
  import { type ModelProfileDefinition } from "./model-profiles";
14
14
  import { GJC_MODEL_ASSIGNMENT_TARGET_IDS, type ModelProfileConfig } from "./models-config-schema";
15
+ import { type EffectiveProviderAuth } from "./provider-selection-policy";
15
16
  import { type Settings } from "./settings";
17
+ export type { EffectiveProviderAuth, ProviderSelectionPolicy } from "./provider-selection-policy";
16
18
  export type { CanonicalModelIndex, CanonicalModelRecord, CanonicalModelVariant, ModelEquivalenceConfig };
17
19
  export { isAuthenticated, kNoAuth };
18
20
  export type ModelRole = "default";
@@ -290,7 +292,7 @@ export declare const ModelsConfigFile: ConfigFile<{
290
292
  profiles?: Record<string, {
291
293
  required_providers: string[];
292
294
  display_name?: string | undefined;
293
- model_mapping: Partial<Record<"architect" | "critic" | "default" | "executor" | "planner", string | string[]>>;
295
+ model_mapping: Partial<Record<"architect" | "critic" | "default" | "executor" | "image" | "planner", string | string[]>>;
294
296
  }> | undefined;
295
297
  }>;
296
298
  /** Provider override config (baseUrl, headers, apiKey, compat, transport) without custom models */
@@ -326,6 +328,8 @@ export interface CanonicalModelQueryOptions {
326
328
  candidates?: readonly Model<Api>[];
327
329
  /** Stable session identity used to keep a canonical variant sticky within a session. */
328
330
  sessionId?: string;
331
+ /** Credential-selection session used to classify effective provider auth. Defaults to sessionId. */
332
+ credentialSessionId?: string;
329
333
  }
330
334
  /**
331
335
  * Model registry - loads and manages models, resolves API keys via AuthStorage.
@@ -371,7 +375,69 @@ export declare class ModelRegistry {
371
375
  getConfiguredProviderIds(): readonly string[];
372
376
  getCanonicalModels(options?: CanonicalModelQueryOptions): CanonicalModelRecord[];
373
377
  getCanonicalVariants(canonicalId: string, options?: CanonicalModelQueryOptions): CanonicalModelVariant[];
378
+ /**
379
+ * Resolve an exact canonical id to a concrete model.
380
+ *
381
+ * Canonical ids remain exact lookup keys, but their provider variant uses the
382
+ * same provider-rank-first policy as preset aliases. Availability filtering
383
+ * remains opt-in through `availableOnly`; final-segment aliases never fall
384
+ * back implicitly — use {@link resolveModelByLookupAlias} for alias intent.
385
+ */
374
386
  resolveCanonicalModel(canonicalId: string, options?: CanonicalModelQueryOptions): Model<Api> | undefined;
387
+ /**
388
+ * Resolve a final-slash-segment alias to a concrete model, explicitly.
389
+ *
390
+ * The alias gathers every matching variant selector from the variant-level
391
+ * alias index — never sibling variants in the same canonical record that end
392
+ * in a different segment — then ranks all eligible variants together by the
393
+ * centralized provider policy (provider-rank-first axis order), with the
394
+ * canonical/exactness axis preserved relative to the alias lookup key
395
+ * (`model.id === alias` beats slash-prefixed ids before source/cost/catalog
396
+ * ties). Fails closed: availability/disabled filtering applies even to
397
+ * supplied candidate arrays, alias variants are intersected with the
398
+ * filtered candidate selectors before ranking, and zero eligible candidates
399
+ * returns an authoritative `undefined` without rewriting the variant's
400
+ * model/wire ids. Winners stay sticky per session.
401
+ */
402
+ resolveModelByLookupAlias(alias: string, options?: CanonicalModelQueryOptions): Model<Api> | undefined;
403
+ /**
404
+ * Whether a final-slash-segment alias is known in the current canonical
405
+ * index. Knownness is decided from the full multi-target alias index and is
406
+ * independent of availability: a known-but-unavailable alias still reports
407
+ * `true` while {@link resolveModelByLookupAlias} returns an authoritative
408
+ * `undefined`.
409
+ */
410
+ lookupAliasExists(alias: string): boolean;
411
+ /**
412
+ * Effective credential provenance for a provider, derived from existing
413
+ * AuthStorage/session credential surfaces (never from token shape).
414
+ * Session-specific provenance wins; API-key surfaces (runtime, config,
415
+ * custom/manual, stored api_key) beat OAuth presence; OAuth remains the
416
+ * provenance when it is the effective remaining stored credential;
417
+ * unknown/keyless providers fall back to non-OAuth.
418
+ */
419
+ getEffectiveProviderAuth(provider: string, sessionId?: string): EffectiveProviderAuth;
420
+ /**
421
+ * Forget a session's remembered canonical variant so the next resolution
422
+ * for that session re-ranks from scratch (explicit reselection
423
+ * integration). Returns whether an entry was actually removed.
424
+ */
425
+ clearCanonicalVariant(sessionId: string): boolean;
426
+ /**
427
+ * Snapshot a session's remembered sticky canonical variant selector — the exact
428
+ * concrete "provider/id" selector, captured verbatim rather than re-derived
429
+ * from any live model. Returns undefined when the session has no remembered
430
+ * variant. The caller owns restoring it later via
431
+ * {@link restoreSessionCanonicalVariant}.
432
+ */
433
+ getSessionCanonicalVariant(sessionId: string): string | undefined;
434
+ /**
435
+ * Restore a session's sticky canonical variant selector exactly, preserving the
436
+ * concrete provider/model previously remembered (never re-derived from a live
437
+ * model). The selector must still be present in the canonical index, otherwise
438
+ * the stale variant is left untouched and `false` is returned.
439
+ */
440
+ restoreSessionCanonicalVariant(sessionId: string, selector: string): boolean;
375
441
  getCanonicalId(model: Model<Api>): string | undefined;
376
442
  /**
377
443
  * Seed a child canonical scope from a concrete parent model without touching
@@ -398,6 +464,7 @@ export declare class ModelRegistry {
398
464
  * Check whether auth is configured for a provider.
399
465
  */
400
466
  hasConfiguredProviderAuth(provider: string): boolean;
467
+ isCredentiallessProvider(provider: string): boolean;
401
468
  getDiscoverableProviders(): string[];
402
469
  getProviderDiscoveryState(provider: string): ProviderDiscoveryState | undefined;
403
470
  /**
@@ -45,7 +45,7 @@ export interface ModelMatchPreferences {
45
45
  /** Providers to deprioritize when no recent usage is available. */
46
46
  deprioritizeProviders?: string[];
47
47
  }
48
- export type CanonicalModelRegistry = Partial<Pick<ModelRegistry, "resolveCanonicalModel" | "getCanonicalVariants" | "getCanonicalId" | "seedCanonicalVariant">>;
48
+ export type CanonicalModelRegistry = Partial<Pick<ModelRegistry, "resolveCanonicalModel" | "getCanonicalVariants" | "getCanonicalId" | "seedCanonicalVariant" | "resolveModelByLookupAlias" | "lookupAliasExists" | "clearCanonicalVariant">>;
49
49
  export type ModelLookupRegistry = Pick<ModelRegistry, "getAvailable"> & Partial<CanonicalModelRegistry>;
50
50
  type CliModelRegistry = Pick<ModelRegistry, "getAll"> & Partial<CanonicalModelRegistry>;
51
51
  type InitialModelRegistry = Pick<ModelRegistry, "getAvailable">;
@@ -67,11 +67,15 @@ export interface ResolveSelectorOptions {
67
67
  modelRegistry?: CanonicalModelRegistry;
68
68
  preferences?: ModelMatchPreferences;
69
69
  sessionId?: string;
70
+ credentialSessionId?: string;
71
+ aliasIntent?: "preset-equivalent" | "reject";
70
72
  }
71
73
  /**
72
74
  * Resolve one selector through ordered exact, canonical, bare-id, provider-fuzzy,
73
- * substring/alias, and glob stages. Thinking is split only after a full selector
74
- * cannot resolve, which preserves OpenRouter route suffixes in concrete IDs.
75
+ * substring/alias, and glob stages. A preset-equivalent alias intent adds a
76
+ * final-slash-segment alias stage between strict-exact and substring/fuzzy.
77
+ * Thinking is split only after a full selector cannot resolve, which preserves
78
+ * OpenRouter route suffixes in concrete IDs.
75
79
  */
76
80
  export declare function resolveSelector(selector: string, candidates: Model<Api>[], options?: ResolveSelectorOptions): ParsedModelResult;
77
81
  /** @internal Exported for testing and legacy adapters. */
@@ -79,6 +83,8 @@ export declare function parseModelPattern(pattern: string, availableModels: Mode
79
83
  allowInvalidThinkingSelectorFallback?: boolean;
80
84
  modelRegistry?: CanonicalModelRegistry;
81
85
  sessionId?: string;
86
+ credentialSessionId?: string;
87
+ aliasIntent?: "preset-equivalent" | "reject";
82
88
  }): ParsedModelResult;
83
89
  /**
84
90
  * Expand a role alias like "pi/default" to the configured model string.
@@ -107,6 +113,8 @@ export declare function resolveModelRoleValue(roleValue: ModelSelectorValue | un
107
113
  matchPreferences?: ModelMatchPreferences;
108
114
  modelRegistry?: CanonicalModelRegistry;
109
115
  sessionId?: string;
116
+ credentialSessionId?: string;
117
+ aliasIntent?: "preset-equivalent" | "reject";
110
118
  }): ResolvedModelRoleValue;
111
119
  export declare function extractExplicitThinkingSelector(value: ModelSelectorValue | undefined, settings?: Settings): ThinkingLevel | undefined;
112
120
  /**
@@ -126,7 +134,7 @@ export declare function resolveModelFromSettings(options: {
126
134
  /**
127
135
  * Resolve a list of override patterns to the first matching model.
128
136
  */
129
- export declare function resolveModelOverride(modelPatterns: string[], modelRegistry: ModelLookupRegistry, settings?: Settings, sessionId?: string): {
137
+ export declare function resolveModelOverride(modelPatterns: string[], modelRegistry: ModelLookupRegistry, settings?: Settings, sessionId?: string, aliasIntent?: "preset-equivalent" | "reject"): {
130
138
  model?: Model<Api>;
131
139
  thinkingLevel?: ThinkingLevel;
132
140
  explicitThinkingLevel: boolean;
@@ -140,6 +148,9 @@ export declare function resolveModelOverride(modelPatterns: string[], modelRegis
140
148
  */
141
149
  export interface ModelChainResolutionOptions {
142
150
  managedFallback?: boolean;
151
+ aliasIntent?: "preset-equivalent" | "reject";
152
+ canonicalSessionId?: string | null;
153
+ credentialSessionId?: string;
143
154
  }
144
155
  export declare function resolveModelChainWithAuth(modelPatterns: readonly string[], modelRegistry: ModelLookupRegistry & Pick<ModelRegistry, "getApiKey">, settings?: Settings, sessionId?: string, options?: ModelChainResolutionOptions): Promise<{
145
156
  model?: Model<Api>;
@@ -140,7 +140,7 @@ export declare const OpenAICompatSchema: z.ZodObject<{
140
140
  }>>;
141
141
  }, z.core.$strip>;
142
142
  export declare const GJC_MODEL_EFFORT_IDS: readonly ["minimal", "low", "medium", "high", "xhigh", "max"];
143
- export declare const GJC_MODEL_ASSIGNMENT_TARGET_IDS: readonly ["default", "executor", "architect", "planner", "critic"];
143
+ export declare const GJC_MODEL_ASSIGNMENT_TARGET_IDS: readonly ["default", "executor", "architect", "planner", "critic", "image"];
144
144
  export declare const EffortSchema: z.ZodEnum<{
145
145
  high: "high";
146
146
  low: "low";
@@ -158,15 +158,17 @@ export declare const ProfileRoleSchema: z.ZodEnum<{
158
158
  critic: "critic";
159
159
  default: "default";
160
160
  executor: "executor";
161
+ image: "image";
161
162
  planner: "planner";
162
163
  }>;
163
- export declare const ProfileModelSelectorPattern: string;
164
+ export declare const ProfileModelSelectorPattern = "^(?:[^,/]+/[^,]*[^,:]|[^/,]*[^/,:])$";
164
165
  export declare const ProfileModelSelectorSchema: z.ZodString;
165
166
  export declare const ProfileModelMappingSchema: z.ZodRecord<z.ZodEnum<{
166
167
  architect: "architect";
167
168
  critic: "critic";
168
169
  default: "default";
169
170
  executor: "executor";
171
+ image: "image";
170
172
  planner: "planner";
171
173
  }> & z.core.$partial, z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
172
174
  export declare const ProfileDefinitionSchema: z.ZodObject<{
@@ -177,6 +179,7 @@ export declare const ProfileDefinitionSchema: z.ZodObject<{
177
179
  critic: "critic";
178
180
  default: "default";
179
181
  executor: "executor";
182
+ image: "image";
180
183
  planner: "planner";
181
184
  }> & z.core.$partial, z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
182
185
  }, z.core.$strict>;
@@ -188,6 +191,7 @@ export declare const ProfilesSchema: z.ZodRecord<z.ZodString, z.ZodObject<{
188
191
  critic: "critic";
189
192
  default: "default";
190
193
  executor: "executor";
194
+ image: "image";
191
195
  planner: "planner";
192
196
  }> & z.core.$partial, z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
193
197
  }, z.core.$strict>>;
@@ -823,6 +827,7 @@ export declare const ModelsConfigSchema: z.ZodObject<{
823
827
  critic: "critic";
824
828
  default: "default";
825
829
  executor: "executor";
830
+ image: "image";
826
831
  planner: "planner";
827
832
  }> & z.core.$partial, z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
828
833
  }, z.core.$strict>>>;
@@ -0,0 +1,62 @@
1
+ import type { Api, Model } from "@gajae-code/ai/core";
2
+ /**
3
+ * Effective credential provenance for a provider, derived from credential
4
+ * surfaces (never from token shape).
5
+ *
6
+ * - `"oauth"`: requests are authenticated with an OAuth-provisioned credential,
7
+ * including OAuth flows whose access tokens happen to look like API keys
8
+ * (e.g. GitHub Copilot `ghu_` tokens).
9
+ * - `"key"`: a manual or configured API key (stored `api_key`, CLI `--api-key`
10
+ * runtime override, `models.yml` `apiKey`/`apiKeyEnv`, or environment key).
11
+ * - `"keyless"`: no credential is required (local servers, `auth: none`).
12
+ * - `"unknown"`: no credential surface is present.
13
+ */
14
+ export type EffectiveProviderAuth = "oauth" | "key" | "keyless" | "unknown";
15
+ export interface ProviderSelectionPolicyInput {
16
+ /** Explicit `modelProviderOrder` from settings; trimmed and case-insensitive. */
17
+ explicitProviderOrder: readonly string[];
18
+ /** Effective auth provenance per lowercased provider id. */
19
+ effectiveAuth: ReadonlyMap<string, EffectiveProviderAuth>;
20
+ /** Registry catalog provider ids, lowercased, first-wins catalog order. */
21
+ catalogProviders: readonly string[];
22
+ /** Registry catalog model selectors ("provider/id"), lowercased, first-wins catalog order. */
23
+ catalogModels: readonly string[];
24
+ }
25
+ export interface ProviderSelectionPolicy {
26
+ /**
27
+ * Total-order rank for a provider: explicit providers `0..n-1`, omitted
28
+ * effective-OAuth providers `n`, omitted non-OAuth/unknown/keyless providers
29
+ * `n+1`. Unknown providers that were never cataloged still receive the
30
+ * non-OAuth rank unless their effective auth is OAuth.
31
+ */
32
+ rank(provider: string): number;
33
+ /** Lowercased explicit provider ids, in explicit order (deduped). */
34
+ explicitProviders(): readonly string[];
35
+ /** Whether a provider was listed explicitly. */
36
+ isExplicit(provider: string): boolean;
37
+ /** Ordered distinct provider ids: explicit order first, then catalog order. */
38
+ orderedProviders(): readonly string[];
39
+ /** Stable catalog index per lowercased provider id (registry-owned tie data). */
40
+ providerCatalogIndex(provider: string): number;
41
+ /** Stable catalog index per lowercased model selector (registry-owned tie data). */
42
+ modelCatalogIndex(selector: string): number;
43
+ }
44
+ /**
45
+ * Build a pure provider selection policy over explicit user order, effective
46
+ * credential provenance, and registry-owned catalog tie data. The policy never
47
+ * reads settings, auth storage, or the model catalog itself — callers pass the
48
+ * current values in so ranking stays deterministic and testable.
49
+ */
50
+ export declare function createProviderSelectionPolicy(input: ProviderSelectionPolicyInput): ProviderSelectionPolicy;
51
+ export interface ProviderSelectionCatalog {
52
+ /** Lowercased provider ids in first-wins registry catalog order. */
53
+ readonly catalogProviders: readonly string[];
54
+ /** Lowercased model selectors in first-wins registry catalog order. */
55
+ readonly catalogModels: readonly string[];
56
+ }
57
+ /**
58
+ * Derive stable provider/model tie data from the registry catalog order, not
59
+ * from a caller-supplied candidate array. First occurrence wins so reordering
60
+ * candidates never changes ranking.
61
+ */
62
+ export declare function buildProviderSelectionCatalog(models: readonly Model<Api>[]): ProviderSelectionCatalog;