@xandreed/plugin-models 0.13.0 → 0.15.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 (151) hide show
  1. package/README.md +1 -1
  2. package/dist/auth/anthropicOAuth.d.ts +45 -11
  3. package/dist/auth/anthropicOAuth.js +23 -23
  4. package/dist/auth/auth-store.conformance.d.ts +63 -0
  5. package/dist/auth/auth-store.conformance.js +152 -0
  6. package/dist/auth/credential-input.entity.d.ts +52 -0
  7. package/dist/auth/credential-input.entity.functions.d.ts +18 -0
  8. package/dist/auth/credential-input.entity.functions.js +12 -0
  9. package/dist/auth/credential-input.entity.js +22 -0
  10. package/dist/auth/credential-refresh.entity.d.ts +17 -0
  11. package/dist/auth/credential-refresh.entity.functions.d.ts +57 -0
  12. package/dist/auth/credential-refresh.entity.functions.js +21 -0
  13. package/dist/auth/credential-refresh.entity.js +2 -0
  14. package/dist/auth/localAuth.d.ts +12 -2
  15. package/dist/auth/localAuth.js +58 -86
  16. package/dist/auth/memory-auth.adapter.d.ts +35 -0
  17. package/dist/auth/memory-auth.adapter.js +35 -0
  18. package/dist/auth/openAiCodexOAuth.d.ts +28 -6
  19. package/dist/auth/openAiCodexOAuth.js +22 -32
  20. package/dist/auth/token-response.entity.d.ts +21 -0
  21. package/dist/auth/token-response.entity.functions.d.ts +20 -0
  22. package/dist/auth/token-response.entity.functions.js +10 -0
  23. package/dist/auth/token-response.entity.js +10 -0
  24. package/dist/compat/index.d.ts +2 -0
  25. package/dist/compat/index.js +1 -0
  26. package/dist/conformance/index.d.ts +6 -0
  27. package/dist/conformance/index.js +3 -0
  28. package/dist/index.d.ts +30 -13
  29. package/dist/index.js +25 -50
  30. package/dist/llm/chat-wire.entity.d.ts +123 -0
  31. package/dist/llm/chat-wire.entity.functions.d.ts +28 -0
  32. package/dist/llm/chat-wire.entity.functions.js +10 -0
  33. package/dist/llm/chat-wire.entity.js +37 -0
  34. package/dist/llm/compat-telemetry.adapter.d.ts +6 -0
  35. package/dist/llm/compat-telemetry.adapter.js +21 -0
  36. package/dist/llm/compat.d.ts +84 -33
  37. package/dist/llm/compat.js +188 -121
  38. package/dist/llm/model-completion.adapter.d.ts +49 -0
  39. package/dist/llm/model-completion.adapter.js +77 -0
  40. package/dist/llm/model-completion.entity.d.ts +4 -0
  41. package/dist/llm/model-completion.entity.functions.d.ts +3 -0
  42. package/dist/llm/model-completion.entity.functions.js +7 -0
  43. package/dist/llm/model-completion.entity.js +7 -0
  44. package/dist/llm/model-retry-policy.entity.d.ts +37 -0
  45. package/dist/llm/model-retry-policy.entity.functions.d.ts +16 -0
  46. package/dist/llm/model-retry-policy.entity.functions.js +33 -0
  47. package/dist/llm/model-retry-policy.entity.js +23 -0
  48. package/dist/llm/model-settings.entity.d.ts +85 -0
  49. package/dist/llm/model-settings.entity.functions.d.ts +11 -0
  50. package/dist/llm/model-settings.entity.functions.js +49 -0
  51. package/dist/llm/model-settings.entity.js +28 -0
  52. package/dist/llm/model-usage.entity.d.ts +61 -0
  53. package/dist/llm/model-usage.entity.functions.d.ts +11 -0
  54. package/dist/llm/model-usage.entity.functions.js +24 -0
  55. package/dist/llm/model-usage.entity.js +19 -0
  56. package/dist/llm/modelCatalog.d.ts +47 -7
  57. package/dist/llm/modelCatalog.js +31 -57
  58. package/dist/llm/openAiCodex.d.ts +18 -7
  59. package/dist/llm/openAiCodex.js +57 -45
  60. package/dist/llm/openAiCodexWebSocket.d.ts +60 -7
  61. package/dist/llm/openAiCodexWebSocket.js +113 -105
  62. package/dist/llm/prompt-cache-frame.entity.d.ts +18 -0
  63. package/dist/llm/prompt-cache-frame.entity.js +10 -0
  64. package/dist/llm/prompt-cache.entity.d.ts +57 -0
  65. package/dist/llm/prompt-cache.entity.functions.d.ts +8 -0
  66. package/dist/llm/prompt-cache.entity.functions.js +73 -0
  67. package/dist/llm/prompt-cache.entity.js +27 -0
  68. package/dist/llm/provider-client.adapter.d.ts +9 -0
  69. package/dist/llm/provider-client.adapter.js +60 -0
  70. package/dist/llm/provider-failure.entity.d.ts +42 -0
  71. package/dist/llm/provider-failure.entity.functions.d.ts +8 -0
  72. package/dist/llm/provider-failure.entity.functions.js +67 -0
  73. package/dist/llm/provider-failure.entity.js +20 -0
  74. package/dist/llm/provider-profile.entity.d.ts +79 -0
  75. package/dist/llm/provider-profile.entity.functions.d.ts +23 -0
  76. package/dist/llm/provider-profile.entity.functions.js +83 -0
  77. package/dist/llm/provider-profile.entity.js +10 -0
  78. package/dist/llm/providers.d.ts +125 -29
  79. package/dist/llm/providers.js +311 -117
  80. package/dist/llm/retry.d.ts +11 -47
  81. package/dist/llm/retry.js +33 -52
  82. package/dist/llm/router.d.ts +56 -28
  83. package/dist/llm/router.js +125 -88
  84. package/dist/llm/sse.d.ts +58 -29
  85. package/dist/llm/sse.js +47 -39
  86. package/dist/llm/thinking-binding.entity.d.ts +49 -0
  87. package/dist/llm/thinking-binding.entity.functions.d.ts +21 -0
  88. package/dist/llm/thinking-binding.entity.functions.js +16 -0
  89. package/dist/llm/thinking-binding.entity.js +11 -0
  90. package/dist/llm/utilityLlm.d.ts +14 -5
  91. package/dist/llm/utilityLlm.js +18 -13
  92. package/dist/plugin.adapter.d.ts +154 -6
  93. package/dist/plugin.adapter.js +53 -10
  94. package/dist/ports/auth-store.port.d.ts +73 -0
  95. package/dist/ports/auth-store.port.js +24 -0
  96. package/dist/ports/host-credentials.port.d.ts +22 -0
  97. package/dist/ports/host-credentials.port.js +4 -0
  98. package/dist/ports/model-call-completion.port.d.ts +9 -0
  99. package/dist/ports/model-call-completion.port.js +2 -0
  100. package/dist/ports/model-endpoints.port.d.ts +66 -19
  101. package/dist/ports/model-endpoints.port.js +22 -4
  102. package/dist/ports/model-retry-policy.port.d.ts +17 -0
  103. package/dist/ports/model-retry-policy.port.js +3 -0
  104. package/dist/ports/model-settings.port.d.ts +32 -0
  105. package/dist/ports/model-settings.port.js +4 -0
  106. package/dist/ports/models-transport.port.d.ts +53 -0
  107. package/dist/ports/models-transport.port.js +7 -0
  108. package/dist/ports/prompt-cache-frame.port.d.ts +21 -0
  109. package/dist/ports/prompt-cache-frame.port.js +4 -0
  110. package/dist/ports/settings-store.port.d.ts +70 -0
  111. package/dist/ports/settings-store.port.js +33 -0
  112. package/dist/ports/thinking-binding.port.d.ts +7 -0
  113. package/dist/ports/thinking-binding.port.js +4 -0
  114. package/dist/settings/localSettings.d.ts +2 -1
  115. package/dist/settings/localSettings.js +18 -61
  116. package/dist/settings/memory-settings.adapter.d.ts +12 -0
  117. package/dist/settings/memory-settings.adapter.js +11 -0
  118. package/dist/settings/roleView.d.ts +3 -1
  119. package/dist/settings/roleView.js +1 -1
  120. package/dist/settings/settings-store.conformance.d.ts +47 -0
  121. package/dist/settings/settings-store.conformance.js +100 -0
  122. package/dist/settings/settings-value.entity.d.ts +15 -0
  123. package/dist/settings/settings-value.entity.functions.d.ts +51 -0
  124. package/dist/settings/settings-value.entity.functions.js +42 -0
  125. package/dist/settings/settings-value.entity.js +2 -0
  126. package/dist/storage/json-file.d.ts +18 -0
  127. package/dist/storage/json-file.js +26 -0
  128. package/dist/transport/http-proxy.entity.d.ts +104 -0
  129. package/dist/transport/http-proxy.entity.functions.d.ts +51 -0
  130. package/dist/transport/http-proxy.entity.functions.js +112 -0
  131. package/dist/transport/http-proxy.entity.js +42 -0
  132. package/dist/transport/model-request.conformance.d.ts +13 -0
  133. package/dist/transport/model-request.conformance.js +36 -0
  134. package/dist/transport/models-transport.adapter.d.ts +49 -0
  135. package/dist/transport/models-transport.adapter.js +99 -0
  136. package/dist/transport/resilient-http-client.adapter.d.ts +73 -0
  137. package/dist/transport/resilient-http-client.adapter.js +177 -0
  138. package/dist/transport/undici-fetch.adapter.d.ts +13 -0
  139. package/dist/transport/undici-fetch.adapter.js +1 -0
  140. package/package.json +13 -6
  141. package/dist/auth/anthropicOAuth.test.d.ts +0 -1
  142. package/dist/auth/localAuth.test.d.ts +0 -1
  143. package/dist/llm/compat.test.d.ts +0 -1
  144. package/dist/llm/modelCatalog.test.d.ts +0 -1
  145. package/dist/llm/providers.test.d.ts +0 -1
  146. package/dist/llm/retry.test.d.ts +0 -1
  147. package/dist/llm/router.test.d.ts +0 -1
  148. package/dist/llm/sse.test.d.ts +0 -1
  149. package/dist/plugin.adapter.test.d.ts +0 -1
  150. package/dist/settings/localSettings.test.d.ts +0 -1
  151. package/dist/settings/roleView.test.d.ts +0 -1
@@ -0,0 +1,73 @@
1
+ import { Context, Option, Schema } from "effect";
2
+ import type { Effect, Redacted } from "effect";
3
+ import type { ProviderId } from "@xandreed/core";
4
+ /**
5
+ * A stored provider credential: a raw API key, an OAuth subscription (with
6
+ * refresh material and absolute expiry, epoch ms), or a local provider that
7
+ * needs no key. Its secrets (`key`, `access`, `refresh`) are `Redacted`, so
8
+ * they print as `<redacted>` in errors, logs and fingerprints; unwrap one
9
+ * with `Redacted.value` only where a request is built. The encoded form is
10
+ * the on-disk `auth.json` vocabulary the previous line established, secrets
11
+ * in the clear, so existing credentials keep working. Store a credential
12
+ * through `Schema.encodeEffect(Credential)`, never `JSON.stringify`, which
13
+ * writes `"<redacted>"` in place of each secret.
14
+ *
15
+ * @public
16
+ */
17
+ export declare const Credential: Schema.Union<readonly [Schema.Struct<{
18
+ readonly type: Schema.Literal<"api_key">;
19
+ readonly key: Schema.RedactedFromValue<Schema.String>;
20
+ }>, Schema.Struct<{
21
+ readonly type: Schema.Literal<"oauth">;
22
+ readonly access: Schema.RedactedFromValue<Schema.String>;
23
+ readonly refresh: Schema.RedactedFromValue<Schema.String>;
24
+ readonly expires: Schema.Number;
25
+ readonly accountId: Schema.optionalKey<Schema.String>;
26
+ readonly installationId: Schema.optionalKey<Schema.String>;
27
+ }>, Schema.Struct<{
28
+ readonly type: Schema.Literal<"local">;
29
+ readonly baseUrl: Schema.optionalKey<Schema.String>;
30
+ }>]>;
31
+ export type Credential = typeof Credential.Type;
32
+ declare const AuthError_base: Schema.Class<AuthError, Schema.TaggedStruct<"AuthError", {
33
+ readonly provider: Schema.String;
34
+ readonly message: Schema.String;
35
+ /**
36
+ * `auth.corrupt`: the store's backing data could not be read or decoded.
37
+ * Nothing was read as absent and nothing was written over it.
38
+ */
39
+ readonly code: Schema.optionalKey<Schema.Literal<"auth.corrupt">>;
40
+ }>, import("effect/Cause").YieldableError>;
41
+ export declare class AuthError extends AuthError_base {
42
+ }
43
+ declare const AuthStore_base: Context.ServiceClass<AuthStore, "@xandreed/core/AuthStore", {
44
+ readonly all: Effect.Effect<ReadonlyMap<string, Credential>, AuthError>;
45
+ readonly get: (p: ProviderId) => Effect.Effect<Option.Option<Credential>, AuthError>;
46
+ readonly resolveKey: (p: ProviderId) => Effect.Effect<Option.Option<Redacted.Redacted<string>>, AuthError>;
47
+ /** Persist a credential (a login). */
48
+ readonly set: (p: ProviderId, credential: Credential) => Effect.Effect<void, AuthError>;
49
+ /** Remove a provider's credential everywhere it is stored (a logout). */
50
+ readonly remove: (p: ProviderId) => Effect.Effect<void, AuthError>;
51
+ }>;
52
+ /**
53
+ * The credential store, read lazily per request: `resolveKey` returns a
54
+ * usable secret (refreshing a near-expiry OAuth token first, and persisting
55
+ * it where the store keeps credentials), so a credential added mid-session
56
+ * takes effect on the next call with no restart. `None` means the provider
57
+ * is not configured. Every secret it hands out, through `get` and `all` as
58
+ * through `resolveKey`, is `Redacted`.
59
+ *
60
+ * One refresh of a credential runs at a time: concurrent calls on one
61
+ * expired token send one token request and share its result. A `set` or
62
+ * `remove` made while that request is in flight wins over the refreshed
63
+ * token. A store whose backing data cannot be read or decoded fails every
64
+ * call with an `AuthError` of code `auth.corrupt` instead of reading it as
65
+ * empty, so no write replaces credentials it could not read.
66
+ * `authStoreConformance` (`@xandreed/plugin-models/conformance`) checks a
67
+ * store against this contract. Its key stays `@xandreed/core/AuthStore`, the
68
+ * package it was first declared in: plugins' `provides` and hosts' bindings
69
+ * name it, so it never changes.
70
+ */
71
+ export declare class AuthStore extends AuthStore_base {
72
+ }
73
+ export {};
@@ -0,0 +1,24 @@
1
+ import { Context, Option, Schema } from "effect";
2
+ const Secret = Schema.RedactedFromValue(Schema.String);
3
+ export const Credential = Schema.Union([
4
+ Schema.Struct({ type: Schema.Literal("api_key"), key: Secret }),
5
+ Schema.Struct({
6
+ type: Schema.Literal("oauth"),
7
+ access: Secret,
8
+ refresh: Secret,
9
+ expires: Schema.Number,
10
+ accountId: Schema.optionalKey(Schema.String),
11
+ installationId: Schema.optionalKey(Schema.String)
12
+ }),
13
+ Schema.Struct({ type: Schema.Literal("local"), baseUrl: Schema.optionalKey(Schema.String) })
14
+ ]);
15
+
16
+ export class AuthError extends Schema.TaggedError()("AuthError", {
17
+ provider: Schema.String,
18
+ message: Schema.String,
19
+ code: Schema.optionalKey(Schema.Literal("auth.corrupt"))
20
+ }) {
21
+ }
22
+
23
+ export class AuthStore extends Context.Service()("@xandreed/core/AuthStore") {
24
+ }
@@ -0,0 +1,22 @@
1
+ import { Context } from "effect";
2
+ import type { Effect, Option } from "effect";
3
+ import type { ProviderId } from "@xandreed/core";
4
+ import type { AuthError } from "./auth-store.port.js";
5
+ import type { CredentialInput } from "../auth/credential-input.entity.js";
6
+ declare const HostCredentials_base: Context.ServiceClass<HostCredentials, "@xandreed/plugin-models/HostCredentials", {
7
+ readonly load: Effect.Effect<ReadonlyMap<string, CredentialInput>, AuthError>;
8
+ readonly save: (provider: ProviderId, credential: Option.Option<CredentialInput>) => Effect.Effect<void, AuthError>;
9
+ }>;
10
+ /**
11
+ * Credentials a host keeps itself (a secrets manager, a database, its own
12
+ * session store), for the models plugin with `storage: "memory"`. `load` is
13
+ * read once, when the plugin starts; `save` is called after every change the
14
+ * AuthStore makes — a login (`set`), a logout (`None`), an OAuth token
15
+ * refreshed in memory — so the host can keep the new value. Secrets cross
16
+ * this port `Redacted`. A failed `save` fails a login or logout (memory is
17
+ * left as it was) but not a refresh: the refreshed token is already the
18
+ * only valid one, so it stays in memory and the failure is logged.
19
+ */
20
+ export declare class HostCredentials extends HostCredentials_base {
21
+ }
22
+ export {};
@@ -0,0 +1,4 @@
1
+ import { Context } from "effect";
2
+
3
+ export class HostCredentials extends Context.Service()("@xandreed/plugin-models/HostCredentials") {
4
+ }
@@ -0,0 +1,9 @@
1
+ import { Context, Option } from "effect";
2
+ import type { ModelSelection } from "@xandreed/core";
3
+ /** Private execution-time purpose; utilities provide Helper without recording another call. */
4
+ export declare const CurrentModelCallPurpose: Context.Reference<"Loop" | "Helper">;
5
+ /** Private invocation metadata; a routed object call can use a provider's text implementation. */
6
+ export declare const CurrentModelCallMethod: Context.Reference<"Text" | "Object" | "Stream">;
7
+ export declare const CurrentModelCallSelection: Context.Reference<Option.Option<ModelSelection>>;
8
+ /** Identifies which logical budget owns inherited invocation metadata. */
9
+ export declare const CurrentModelCallMetadataOwner: Context.Reference<Option.Option<string & import("effect/Brand").Brand<"ModelCallId">>>;
@@ -0,0 +1,2 @@
1
+ import { Context, Option } from "effect";
2
+ export const CurrentModelCallPurpose = Context.Reference("@xandreed/plugin-models/CurrentModelCallPurpose", { defaultValue: () => "Loop" }), CurrentModelCallMethod = Context.Reference("@xandreed/plugin-models/CurrentModelCallMethod", { defaultValue: () => "Text" }), CurrentModelCallSelection = Context.Reference("@xandreed/plugin-models/CurrentModelCallSelection", { defaultValue: () => Option.none() }), CurrentModelCallMetadataOwner = Context.Reference("@xandreed/plugin-models/CurrentModelCallMetadataOwner", { defaultValue: () => Option.none() });
@@ -1,33 +1,80 @@
1
1
  import { Context, Schema } from "effect";
2
+ /** A base URL using chat completions, or an explicit Anthropic Messages protocol. @public */
3
+ export declare const ModelEndpoint: Schema.Union<readonly [Schema.Struct<{
4
+ /** Absent keeps the existing chat-completions protocol. */
5
+ readonly api: Schema.optionalKey<Schema.Literal<"chat-completions">>;
6
+ readonly standardOnly: Schema.optionalKey<Schema.Boolean>;
7
+ readonly url: Schema.String;
8
+ readonly apiKey: Schema.optionalKey<Schema.Union<readonly [Schema.String, Schema.Redacted<Schema.String>]>>;
9
+ readonly apiKeyEnv: Schema.optionalKey<Schema.String>;
10
+ readonly images: Schema.optionalKey<Schema.Boolean>;
11
+ }>, Schema.Struct<{
12
+ readonly api: Schema.Literal<"anthropic-messages">;
13
+ /** The API key is opaque in either header; omission uses x-api-key. */
14
+ readonly auth: Schema.optionalKey<Schema.Literals<readonly ["x-api-key", "bearer"]>>;
15
+ /** False disables framework caching and refuses caller cache controls. */
16
+ readonly cacheControl: Schema.optionalKey<Schema.Boolean>;
17
+ /** Preserve the pinned SDK's version by default; an explicit version is sent verbatim. */
18
+ readonly apiVersion: Schema.optionalKey<Schema.String>;
19
+ /** Added to the SDK's own beta flags, in order with duplicates removed. */
20
+ readonly betas: Schema.optionalKey<Schema.$Array<Schema.String>>;
21
+ readonly url: Schema.String;
22
+ readonly apiKey: Schema.optionalKey<Schema.Union<readonly [Schema.String, Schema.Redacted<Schema.String>]>>;
23
+ readonly apiKeyEnv: Schema.optionalKey<Schema.String>;
24
+ readonly images: Schema.optionalKey<Schema.Boolean>;
25
+ }>]>;
26
+ export type ModelEndpoint = typeof ModelEndpoint.Type;
2
27
  /**
3
- * An OpenAI-compatible endpoint a host names in configuration: the model
4
- * `<name>:<model id>` is sent to `<url>/chat/completions`. The key is
5
- * optional — a local server or a private gateway may need none. It comes
6
- * from `apiKey`, then the environment variable `apiKeyEnv` names, then the
7
- * AuthStore's key for `<name>`; with none, no Authorization header is sent.
8
- * `standardOnly` (default true) sends only standard chat-completions fields.
28
+ * Endpoints by provider name; a name that matches a built-in provider replaces it.
29
+ *
30
+ * @public
9
31
  */
10
- export declare const ModelEndpoint: Schema.Struct<{
32
+ export declare const ModelEndpoints: Schema.$Record<Schema.String, Schema.Union<readonly [Schema.Struct<{
33
+ /** Absent keeps the existing chat-completions protocol. */
34
+ readonly api: Schema.optionalKey<Schema.Literal<"chat-completions">>;
35
+ readonly standardOnly: Schema.optionalKey<Schema.Boolean>;
11
36
  readonly url: Schema.String;
12
- readonly apiKey: Schema.optionalKey<Schema.String>;
37
+ readonly apiKey: Schema.optionalKey<Schema.Union<readonly [Schema.String, Schema.Redacted<Schema.String>]>>;
13
38
  readonly apiKeyEnv: Schema.optionalKey<Schema.String>;
14
- readonly standardOnly: Schema.optionalKey<Schema.Boolean>;
15
- }>;
16
- export type ModelEndpoint = typeof ModelEndpoint.Type;
17
- /** Endpoints by provider name; a name that matches a built-in provider replaces it. */
18
- export declare const ModelEndpoints: Schema.$Record<Schema.String, Schema.Struct<{
39
+ readonly images: Schema.optionalKey<Schema.Boolean>;
40
+ }>, Schema.Struct<{
41
+ readonly api: Schema.Literal<"anthropic-messages">;
42
+ /** The API key is opaque in either header; omission uses x-api-key. */
43
+ readonly auth: Schema.optionalKey<Schema.Literals<readonly ["x-api-key", "bearer"]>>;
44
+ /** False disables framework caching and refuses caller cache controls. */
45
+ readonly cacheControl: Schema.optionalKey<Schema.Boolean>;
46
+ /** Preserve the pinned SDK's version by default; an explicit version is sent verbatim. */
47
+ readonly apiVersion: Schema.optionalKey<Schema.String>;
48
+ /** Added to the SDK's own beta flags, in order with duplicates removed. */
49
+ readonly betas: Schema.optionalKey<Schema.$Array<Schema.String>>;
19
50
  readonly url: Schema.String;
20
- readonly apiKey: Schema.optionalKey<Schema.String>;
51
+ readonly apiKey: Schema.optionalKey<Schema.Union<readonly [Schema.String, Schema.Redacted<Schema.String>]>>;
21
52
  readonly apiKeyEnv: Schema.optionalKey<Schema.String>;
22
- readonly standardOnly: Schema.optionalKey<Schema.Boolean>;
23
- }>>;
53
+ readonly images: Schema.optionalKey<Schema.Boolean>;
54
+ }>]>>;
24
55
  export type ModelEndpoints = typeof ModelEndpoints.Type;
25
- /** The endpoints the models plugin was configured with; none by default. */
56
+ /**
57
+ * The endpoints the models plugin was configured with; none by default.
58
+ *
59
+ * @public
60
+ */
26
61
  export declare const CurrentModelEndpoints: Context.Reference<{
27
62
  readonly [x: string]: {
28
63
  readonly url: string;
29
- readonly apiKey?: string;
30
- readonly apiKeyEnv?: string;
64
+ readonly images?: boolean;
65
+ readonly apiKey?: string | import("effect/Redacted").Redacted<string>;
66
+ readonly api?: "chat-completions";
31
67
  readonly standardOnly?: boolean;
68
+ readonly apiKeyEnv?: string;
69
+ } | {
70
+ readonly url: string;
71
+ readonly api: "anthropic-messages";
72
+ readonly images?: boolean;
73
+ readonly apiKey?: string | import("effect/Redacted").Redacted<string>;
74
+ readonly auth?: "x-api-key" | "bearer";
75
+ readonly apiKeyEnv?: string;
76
+ readonly cacheControl?: boolean;
77
+ readonly apiVersion?: string;
78
+ readonly betas?: readonly string[];
32
79
  };
33
80
  }>;
@@ -1,9 +1,27 @@
1
1
  import { Context, Schema } from "effect";
2
- export const ModelEndpoint = Schema.Struct({
2
+ const endpointFields = {
3
3
  url: Schema.String,
4
- apiKey: Schema.optionalKey(Schema.String),
4
+ apiKey: Schema.optionalKey(Schema.Union([
5
+ Schema.String,
6
+ Schema.Redacted(Schema.String).annotate({ message: "apiKey is a string or a Redacted string" })
7
+ ]).annotate({ message: "apiKey is a string or a Redacted string" })),
5
8
  apiKeyEnv: Schema.optionalKey(Schema.String),
6
- standardOnly: Schema.optionalKey(Schema.Boolean)
7
- }), ModelEndpoints = Schema.Record(Schema.String, ModelEndpoint), CurrentModelEndpoints = Context.Reference("@xandreed/plugin-models/CurrentModelEndpoints", {
9
+ images: Schema.optionalKey(Schema.Boolean)
10
+ };
11
+ export const ModelEndpoint = Schema.Union([
12
+ Schema.Struct({
13
+ ...endpointFields,
14
+ api: Schema.optionalKey(Schema.Literal("chat-completions")),
15
+ standardOnly: Schema.optionalKey(Schema.Boolean)
16
+ }).annotate({ messageUnexpectedKey: "not an option of a chat-completions endpoint" }),
17
+ Schema.Struct({
18
+ ...endpointFields,
19
+ api: Schema.Literal("anthropic-messages"),
20
+ auth: Schema.optionalKey(Schema.Literals(["x-api-key", "bearer"])),
21
+ cacheControl: Schema.optionalKey(Schema.Boolean),
22
+ apiVersion: Schema.optionalKey(Schema.String.check(Schema.isPattern(/^\d{4}-\d{2}-\d{2}$/))),
23
+ betas: Schema.optionalKey(Schema.Array(Schema.String.check(Schema.isPattern(/^[A-Za-z0-9][A-Za-z0-9._-]*$/))))
24
+ }).annotate({ messageUnexpectedKey: "not an option of an anthropic-messages endpoint" })
25
+ ]).annotate({ messageUnexpectedKey: "not an option of a model endpoint" }), ModelEndpoints = Schema.Record(Schema.String, ModelEndpoint), CurrentModelEndpoints = Context.Reference("@xandreed/plugin-models/CurrentModelEndpoints", {
8
26
  defaultValue: () => ({})
9
27
  });
@@ -0,0 +1,17 @@
1
+ import { Context, Option } from "effect";
2
+ import type { ModelRequestCall } from "../transport/resilient-http-client.adapter.js";
3
+ /** Read when a logical model call executes; the complete policy overrides the defaults. @public */
4
+ export declare const CurrentModelRetryPolicy: Context.Reference<{
5
+ readonly maxAttempts: number;
6
+ readonly requestTimeoutMs: number;
7
+ readonly bodyIdleTimeoutMs: number;
8
+ readonly totalTimeoutMs: number;
9
+ readonly retryAfterMaxMs: number;
10
+ readonly backoff: {
11
+ readonly initialMs: number;
12
+ readonly maxMs: number;
13
+ readonly jitter: number;
14
+ };
15
+ }>;
16
+ /** Private per-call counter/deadline, shared only by its primary and fallback rung. */
17
+ export declare const CurrentModelRequestCall: Context.Reference<Option.Option<ModelRequestCall>>;
@@ -0,0 +1,3 @@
1
+ import { Context, Option } from "effect";
2
+ import { modelRetryDefaults } from "../llm/model-retry-policy.entity.js";
3
+ export const CurrentModelRetryPolicy = Context.Reference("@xandreed/plugin-models/CurrentModelRetryPolicy", { defaultValue: () => modelRetryDefaults }), CurrentModelRequestCall = Context.Reference("@xandreed/plugin-models/CurrentModelRequestCall", { defaultValue: () => Option.none() });
@@ -0,0 +1,32 @@
1
+ import { Context } from "effect";
2
+ /** Static per-model settings captured where the models layer is built. @public */
3
+ export declare const CurrentModelSettings: Context.Reference<{
4
+ readonly [x: string]: {
5
+ readonly effort?: "none" | "low" | "medium" | "high" | "xhigh" | "max";
6
+ readonly limits?: {
7
+ readonly maxOutputTokens?: number;
8
+ readonly contextWindow?: number;
9
+ };
10
+ readonly thinking?: {
11
+ readonly _tag: "Off";
12
+ } | {
13
+ readonly _tag: "Adaptive";
14
+ readonly display?: "omitted" | "summarized";
15
+ } | {
16
+ readonly _tag: "Budget";
17
+ readonly budgetTokens: number;
18
+ readonly display?: "omitted" | "summarized";
19
+ } | {
20
+ readonly _tag: "BetweenTools";
21
+ };
22
+ readonly promptCache?: {
23
+ readonly _tag: "Auto";
24
+ readonly ttl: "5m" | "1h";
25
+ } | {
26
+ readonly _tag: "TopLevel";
27
+ readonly ttl: "5m" | "1h";
28
+ } | {
29
+ readonly _tag: "Off";
30
+ };
31
+ };
32
+ }>;
@@ -0,0 +1,4 @@
1
+ import { Context } from "effect";
2
+ export const CurrentModelSettings = Context.Reference("@xandreed/plugin-models/CurrentModelSettings", {
3
+ defaultValue: () => ({})
4
+ });
@@ -0,0 +1,53 @@
1
+ import { Context, Option } from "effect";
2
+ import type { Effect, Redacted } from "effect";
3
+ import type { Agent } from "node:http";
4
+ import type { ProxyUnsupported } from "../transport/http-proxy.entity.js";
5
+ /**
6
+ * A fetch for the models plugin's HTTP calls: a URL (string or `URL`) and a
7
+ * `RequestInit`, as the provider clients, the OpenAI-compatible client and
8
+ * the OAuth token requests call it. Any `fetch` is one.
9
+ */
10
+ export type ModelsFetch = (input: string | URL, init?: RequestInit) => Promise<Response>;
11
+ /**
12
+ * How a WebSocket reaches its target. `Agent` is for Node only: the agent
13
+ * the `ws` client connects with (one that tunnels through the proxy with
14
+ * CONNECT, or a plain one for a direct connection). `Proxy` is for Bun only:
15
+ * the proxy URL Bun's own `WebSocket` takes as its `proxy` option. A route
16
+ * the runtime cannot use (`Proxy` outside Bun, `Agent` on Bun, whose `ws`
17
+ * stand-in takes neither) fails the call rather than connecting past the
18
+ * proxy.
19
+ *
20
+ * @public
21
+ */
22
+ export type WebSocketProxy = {
23
+ readonly _tag: "Agent";
24
+ readonly agent: Agent;
25
+ } | {
26
+ readonly _tag: "Proxy";
27
+ readonly url: Redacted.Redacted<string>;
28
+ };
29
+ declare const ModelsTransport_base: Context.ServiceClass<ModelsTransport, "@xandreed/plugin-models/ModelsTransport", {
30
+ readonly fetch: ModelsFetch;
31
+ readonly webSocketAgent?: (target: URL) => Effect.Effect<Option.Option<WebSocketProxy>, ProxyUnsupported>;
32
+ }>;
33
+ /**
34
+ * The network path of the models plugin: every HTTP call it makes (the
35
+ * provider SDKs, the OpenAI-compatible client, OAuth token requests) goes
36
+ * through `fetch`, and the OpenAI subscription's WebSocket asks
37
+ * `webSocketAgent` how to reach its target: `None` connects the runtime's
38
+ * default way (direct, unless the runtime applies an environment proxy
39
+ * itself, as Node's global agents do under `NODE_USE_ENV_PROXY`),
40
+ * `ProxyUnsupported` refuses (a proxy applies that this runtime cannot
41
+ * tunnel a WebSocket through). Without `webSocketAgent`, WebSockets connect
42
+ * the default way. `ModelsTransportLive` builds one from a proxy setting and
43
+ * the environment; a host provides its own (a fetch with client
44
+ * certificates, say) through `Agent.define({ services })`.
45
+ */
46
+ export declare class ModelsTransport extends ModelsTransport_base {
47
+ }
48
+ /** Internal provenance: only this exact managed direct instance yields to an explicit call-local fetch. */
49
+ export declare const CurrentManagedModelsTransport: Context.Reference<Option.Option<{
50
+ readonly fetch: ModelsFetch;
51
+ readonly webSocketAgent?: (target: URL) => Effect.Effect<Option.Option<WebSocketProxy>, ProxyUnsupported>;
52
+ }>>;
53
+ export {};
@@ -0,0 +1,7 @@
1
+ import { Context, Option } from "effect";
2
+
3
+ export class ModelsTransport extends Context.Service()("@xandreed/plugin-models/ModelsTransport") {
4
+ }
5
+ export const CurrentManagedModelsTransport = Context.Reference("@xandreed/plugin-models/CurrentManagedModelsTransport", {
6
+ defaultValue: Option.none
7
+ });
@@ -0,0 +1,21 @@
1
+ import { Context } from "effect";
2
+ /** A captured SDK client reads this immutable frame in the invoking call's fiber. */
3
+ export declare const CurrentPromptCacheFrame: Context.Reference<{
4
+ readonly candidates: readonly {
5
+ readonly control: {
6
+ readonly type: "ephemeral";
7
+ readonly ttl?: "5m" | "1h";
8
+ };
9
+ readonly priority: number;
10
+ }[];
11
+ readonly policy: {
12
+ readonly _tag: "Auto";
13
+ readonly ttl: "5m" | "1h";
14
+ } | {
15
+ readonly _tag: "TopLevel";
16
+ readonly ttl: "5m" | "1h";
17
+ } | {
18
+ readonly _tag: "Off";
19
+ };
20
+ readonly capability: boolean;
21
+ }>;
@@ -0,0 +1,4 @@
1
+ import { Context } from "effect";
2
+ export const CurrentPromptCacheFrame = Context.Reference("@xandreed/plugin-models/CurrentPromptCacheFrame", {
3
+ defaultValue: () => ({ candidates: [], policy: { _tag: "Off" }, capability: !0 })
4
+ });
@@ -0,0 +1,70 @@
1
+ import { Context, Effect, Option, Schema } from "effect";
2
+ declare const EngineSettings_base: Schema.Class<EngineSettings, Schema.Struct<{
3
+ readonly model: Schema.withConstructorDefault<Schema.OptionFromOptional<Schema.Codec<string, string, never, never>>>;
4
+ readonly codeModel: Schema.withConstructorDefault<Schema.OptionFromOptional<Schema.Codec<string, string, never, never>>>;
5
+ readonly fastModel: Schema.withConstructorDefault<Schema.OptionFromOptional<Schema.Codec<string, string, never, never>>>;
6
+ readonly fallbackModel: Schema.withConstructorDefault<Schema.OptionFromOptional<Schema.Codec<string, string, never, never>>>;
7
+ readonly maxAttempts: Schema.withConstructorDefault<Schema.OptionFromOptional<Schema.Codec<number, number, never, never>>>;
8
+ readonly budgetMillis: Schema.withConstructorDefault<Schema.OptionFromOptional<Schema.Codec<number, number, never, never>>>;
9
+ /** Selected after the model because the accepted levels are model-specific. */
10
+ readonly reasoningEffort: Schema.withConstructorDefault<Schema.OptionFromOptional<Schema.Codec<"none" | "low" | "medium" | "high" | "xhigh" | "max", "none" | "low" | "medium" | "high" | "xhigh" | "max", never, never>>>;
11
+ readonly codeReasoningEffort: Schema.withConstructorDefault<Schema.OptionFromOptional<Schema.Codec<"none" | "low" | "medium" | "high" | "xhigh" | "max", "none" | "low" | "medium" | "high" | "xhigh" | "max", never, never>>>;
12
+ readonly fastReasoningEffort: Schema.withConstructorDefault<Schema.OptionFromOptional<Schema.Codec<"none" | "low" | "medium" | "high" | "xhigh" | "max", "none" | "low" | "medium" | "high" | "xhigh" | "max", never, never>>>;
13
+ }>, {}>;
14
+ /** @public */
15
+ export declare class EngineSettings extends EngineSettings_base {
16
+ }
17
+ declare const SettingsError_base: Schema.Class<SettingsError, Schema.TaggedStruct<"SettingsError", {
18
+ readonly message: Schema.String;
19
+ /**
20
+ * `settings.corrupt`: the store's backing data could not be read or
21
+ * decoded. Nothing was read as defaults and nothing was written over it.
22
+ */
23
+ readonly code: Schema.optionalKey<Schema.Literal<"settings.corrupt">>;
24
+ }>, import("effect/Cause").YieldableError>;
25
+ /** @public */
26
+ export declare class SettingsError extends SettingsError_base {
27
+ }
28
+ /**
29
+ * The three model roles a selection can be persisted under.
30
+ *
31
+ * @public
32
+ */
33
+ export type ModelRole = "general" | "code" | "fast";
34
+ /** The non-role keys the keyed setter may write — a closed vocabulary, so a
35
+ * typo can never land a dead key in the user's config.
36
+ *
37
+ * @public
38
+ */
39
+ export declare const SETTINGS_KEYS: readonly ["fallbackModel", "maxAttempts", "budgetMillis", "reasoningEffort", "codeReasoningEffort", "fastReasoningEffort"];
40
+ /** @public */
41
+ export type SettingsKey = (typeof SETTINGS_KEYS)[number];
42
+ declare const SettingsStore_base: Context.ServiceClass<SettingsStore, "@xandreed/core/SettingsStore", {
43
+ readonly load: Effect.Effect<EngineSettings, SettingsError>;
44
+ /** Persist one role's model selection (a role choice); `None` clears
45
+ * the role so it falls back to its default again. A selection that is
46
+ * not `"<provider>:<modelId>"` fails with a `SettingsError` and writes
47
+ * nothing. */
48
+ readonly setRole: (role: ModelRole, selection: Option.Option<string>) => Effect.Effect<void, SettingsError>;
49
+ /** Persist one non-role key from its STRING form (a settings edit): the
50
+ * adapter validates + coerces per key ("true", "3", "provider:model")
51
+ * and rejects a value that doesn't parse with a `SettingsError`,
52
+ * writing nothing; `None` clears the key. */
53
+ readonly set: (key: SettingsKey, value: Option.Option<string>) => Effect.Effect<void, SettingsError>;
54
+ }>;
55
+ /**
56
+ * Read-through settings port. `load` re-reads the backing store on every call
57
+ * so a value changed mid-session takes effect on the next turn — callers must
58
+ * not cache the result across turns. A store may be read-only: then
59
+ * `setRole` and `set` fail with a `SettingsError` and write nothing. A store
60
+ * whose backing data cannot be read or decoded fails `load` and every write
61
+ * with a `SettingsError` of code `settings.corrupt` instead of reading it as
62
+ * defaults, so no write replaces settings it could not read.
63
+ * `settingsStoreConformance` (`@xandreed/plugin-models/conformance`) checks
64
+ * a store against this contract. Its key stays `@xandreed/core/SettingsStore`,
65
+ * the package it was first declared in: plugins' `provides` and hosts'
66
+ * bindings name it, so it never changes.
67
+ */
68
+ export declare class SettingsStore extends SettingsStore_base {
69
+ }
70
+ export {};
@@ -0,0 +1,33 @@
1
+ import { Context, Effect, Option, Schema } from "effect";
2
+ import { ReasoningEffort } from "@xandreed/core";
3
+ const optionField = (schema) => Schema.OptionFromOptional(schema).pipe(Schema.withConstructorDefault(Effect.succeed(Option.none())));
4
+
5
+ export class EngineSettings extends Schema.Class("EngineSettings")({
6
+ model: optionField(Schema.String),
7
+ codeModel: optionField(Schema.String),
8
+ fastModel: optionField(Schema.String),
9
+ fallbackModel: optionField(Schema.String),
10
+ maxAttempts: optionField(Schema.Number),
11
+ budgetMillis: optionField(Schema.Number),
12
+ reasoningEffort: optionField(ReasoningEffort),
13
+ codeReasoningEffort: optionField(ReasoningEffort),
14
+ fastReasoningEffort: optionField(ReasoningEffort)
15
+ }) {
16
+ }
17
+
18
+ export class SettingsError extends Schema.TaggedError()("SettingsError", {
19
+ message: Schema.String,
20
+ code: Schema.optionalKey(Schema.Literal("settings.corrupt"))
21
+ }) {
22
+ }
23
+ export const SETTINGS_KEYS = [
24
+ "fallbackModel",
25
+ "maxAttempts",
26
+ "budgetMillis",
27
+ "reasoningEffort",
28
+ "codeReasoningEffort",
29
+ "fastReasoningEffort"
30
+ ];
31
+
32
+ export class SettingsStore extends Context.Service()("@xandreed/core/SettingsStore") {
33
+ }
@@ -0,0 +1,7 @@
1
+ import { Context } from "effect";
2
+ /**
3
+ * What the models plugin was configured to tell a model that binds thinking
4
+ * to the conversation (`thinkingPrefixMismatch`): `drop_block` for adaptive thinking by default;
5
+ * `provider-default` opts out of the explicit binding field.
6
+ */
7
+ export declare const CurrentThinkingPrefixMismatch: Context.Reference<"error" | "provider-default" | "drop_block">;
@@ -0,0 +1,4 @@
1
+ import { Context } from "effect";
2
+ export const CurrentThinkingPrefixMismatch = Context.Reference("@xandreed/plugin-models/CurrentThinkingPrefixMismatch", {
3
+ defaultValue: () => "drop_block"
4
+ });
@@ -1,3 +1,4 @@
1
1
  import { Layer } from "effect";
2
- import { SettingsStore } from "@xandreed/core";
2
+ import { SettingsStore } from "../ports/settings-store.port.js";
3
+ /** @public */
3
4
  export declare const LocalSettingsStoreLive: (cwd: string, home: string) => Layer.Layer<SettingsStore, never, never>;