@inkdropapp/ai 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inkdropapp/ai",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "AI integration common module",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -8,9 +8,9 @@
8
8
  "scripts": {
9
9
  "lint": "eslint src __tests__",
10
10
  "test": "node --experimental-vm-modules --no-warnings=ExperimentalWarning node_modules/jest/bin/jest.js --config jest.config.cjs --runInBand",
11
- "gen": "tsc --declaration --emitDeclarationOnly",
11
+ "build": "tsc --declaration --emitDeclarationOnly",
12
12
  "format": "prettier --write .",
13
- "prepublishOnly": "npm-run-all lint test gen"
13
+ "prepublishOnly": "npm-run-all lint test build"
14
14
  },
15
15
  "keywords": [
16
16
  "ai",
@@ -25,7 +25,8 @@
25
25
  "@ai-sdk/provider": "4.0.0-beta.14",
26
26
  "@inkdropapp/ai-catalog": "^0.1.0",
27
27
  "@napi-rs/keyring": "^1.2.0",
28
- "ai": "7.0.0-beta.116"
28
+ "ai": "7.0.0-beta.116",
29
+ "npm-run-all2": "^8.0.4"
29
30
  },
30
31
  "devDependencies": {
31
32
  "@types/jest": "^30.0.0",
@@ -33,7 +34,6 @@
33
34
  "eslint": "^10.3.0",
34
35
  "eslint-config-prettier": "^10.1.8",
35
36
  "jest": "^30.4.2",
36
- "npm-run-all": "^4.1.5",
37
37
  "prettier": "^3.8.3",
38
38
  "ts-jest": "^29.4.9",
39
39
  "typescript": "^6.0.3",
package/types/index.d.ts CHANGED
@@ -7,4 +7,4 @@ export { KeyStore, type KeyStoreOptions } from './key-store.js';
7
7
  export { normalizeBaseURL } from './url.js';
8
8
  export { AnthropicProvider } from './providers/anthropic.js';
9
9
  export { OpenAICompatibleProvider, deriveEnvVarName } from './providers/openai-compatible.js';
10
- export { Registry, type RegistryOptions, type ResolvedSlot } from './registry.js';
10
+ export { AIRegistry, type AIRegistryOptions, type ResolvedSlot } from './registry.js';
@@ -45,7 +45,10 @@ export interface AIModel {
45
45
  * OpenAI-compatible providers (OpenRouter, Together, Ollama, …) are modelled.
46
46
  */
47
47
  export interface AIProvider {
48
- /** Stable provider id; appears in `AISettings.slots[*].providerId`. */
48
+ /**
49
+ * Stable provider id; appears in both `AISettings.providerId` and
50
+ * `AISettings.slots[*].providerId`.
51
+ */
49
52
  readonly id: string;
50
53
  /** Human-readable label. */
51
54
  readonly name: string;
@@ -8,13 +8,13 @@ export type ResolvedSlot = {
8
8
  provider: AIProvider;
9
9
  model: AIModel;
10
10
  };
11
- export type RegistryOptions = {
11
+ export type AIRegistryOptions = {
12
12
  settings: AISettings;
13
13
  /**
14
14
  * Optional server-distributed catalogue of supported models per provider.
15
15
  * When omitted, each provider uses its compiled-in defaults (e.g. `ANTHROPIC_MODELS`).
16
16
  * The host typically fetches this from an API and either passes it at
17
- * construction time or swaps it in later via {@link Registry.updateCatalog}.
17
+ * construction time or swaps it in later via {@link AIRegistry.updateCatalog}.
18
18
  */
19
19
  catalog?: AIModelCatalog;
20
20
  /** Pass an existing `KeyStore` to share its in-memory cache across registries. */
@@ -26,25 +26,25 @@ export type RegistryOptions = {
26
26
  * Owns one instance of every configured provider, resolves task slots with
27
27
  * fallback, and is the only place feature code calls to start a completion.
28
28
  *
29
- * The `Registry` is stateless beyond its provider list — it doesn't observe
30
- * settings on its own. Call {@link Registry.updateSettings} when settings
29
+ * The `AIRegistry` is stateless beyond its provider list — it doesn't observe
30
+ * settings on its own. Call {@link AIRegistry.updateSettings} when settings
31
31
  * change to rebuild providers.
32
32
  *
33
33
  * @example
34
34
  * ```ts
35
- * const registry = new Registry({ settings })
35
+ * const registry = new AIRegistry({ settings })
36
36
  * const events = await registry.streamCompletion('default', { messages })
37
37
  * for await (const event of events) {
38
38
  * if (event.kind === 'text-delta') process.stdout.write(event.delta)
39
39
  * }
40
40
  * ```
41
41
  */
42
- export declare class Registry {
42
+ export declare class AIRegistry {
43
43
  readonly keyStore: KeyStore;
44
44
  private providers;
45
45
  private settings;
46
46
  private catalog;
47
- constructor(options: RegistryOptions);
47
+ constructor(options: AIRegistryOptions);
48
48
  /** All configured providers, sorted alphabetically by id. */
49
49
  listProviders(): AIProvider[];
50
50
  getProvider(id: string): AIProvider | undefined;
@@ -59,12 +59,17 @@ export declare class Registry {
59
59
  * Order:
60
60
  * 1. Explicit binding `settings.slots[slot]`, if both provider and model resolve.
61
61
  * 2. For `'fast'` only: fall back to `settings.slots.default`.
62
- * 3. First authenticated provider in alphabetical id order, taking that
62
+ * 3. Preferred provider `settings.providerId`, if that provider is configured,
63
+ * taking its `defaultModel()` (or `defaultFastModel()` for the fast slot).
64
+ * Authentication is not gated here — the user explicitly picked this
65
+ * provider; auth errors surface at stream time rather than silently
66
+ * swapping providers.
67
+ * 4. First authenticated provider in alphabetical id order, taking that
63
68
  * provider's `defaultModel()` (or `defaultFastModel()` for the fast slot).
64
69
  * Mirrors Zed's `available_fallback_model` without the Zed-Cloud preference.
65
- * 4. `undefined` if no provider can satisfy the slot.
70
+ * 5. `undefined` if no provider can satisfy the slot.
66
71
  *
67
- * Async because the third step calls `provider.isAuthenticated()`, which may
72
+ * Async because the fourth step calls `provider.isAuthenticated()`, which may
68
73
  * touch the keyring.
69
74
  */
70
75
  resolveSlot(slot: SlotName): Promise<ResolvedSlot | undefined>;
@@ -72,7 +77,7 @@ export declare class Registry {
72
77
  /**
73
78
  * Streams a completion for a task slot.
74
79
  *
75
- * Resolves the slot via {@link Registry.resolveSlot}; throws {@link NoApiKey}
80
+ * Resolves the slot via {@link AIRegistry.resolveSlot}; throws {@link NoApiKey}
76
81
  * if no provider can satisfy it (no slot binding, and no authenticated
77
82
  * provider available for the implicit fallback). Otherwise returns the
78
83
  * model's stream — note that *upstream* errors (auth, rate limit, etc.)
@@ -77,7 +77,7 @@ export type AnthropicProviderConfig = CommonProviderConfig & {
77
77
  };
78
78
  /**
79
79
  * Top-level AI configuration. The host (Inkdrop main process) constructs this
80
- * from whichever persistence layer it uses and passes it to `Registry`.
80
+ * from whichever persistence layer it uses and passes it to `AIRegistry`.
81
81
  *
82
82
  * The library never reads or writes settings to disk itself.
83
83
  */
@@ -87,8 +87,17 @@ export type AISettings = {
87
87
  openaiCompatible?: OpenAICompatibleProviderConfig[];
88
88
  };
89
89
  /**
90
- * Per-slot model overrides. Unset slots fall back to the first registered
91
- * provider's `defaultModel` / `defaultFastModel`.
90
+ * Preferred provider for every task slot. When set (and the per-slot
91
+ * `slots[slot]` override isn't), each slot resolves to this provider's
92
+ * `defaultModel` / `defaultFastModel`. This is the simple UI knob — bind it
93
+ * to a single "AI provider" dropdown.
94
+ */
95
+ providerId?: string;
96
+ /**
97
+ * Per-slot `(provider, model)` overrides. Wins over `providerId` when set.
98
+ * Useful for advanced configurations that pin a specific model per slot or
99
+ * mix providers across slots (e.g. Claude for `default`, a local model for
100
+ * `fast`).
92
101
  */
93
102
  slots?: Partial<Record<SlotName, SlotConfig>>;
94
103
  };