@xandreed/plugin-models 0.11.0 → 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.
- package/README.md +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -0
- package/dist/llm/compat.d.ts +2 -2
- package/dist/llm/compat.js +1 -1
- package/dist/llm/providers.d.ts +5 -2
- package/dist/llm/providers.js +18 -2
- package/dist/plugin.adapter.d.ts +16 -0
- package/dist/plugin.adapter.js +5 -4
- package/dist/ports/model-endpoints.port.d.ts +33 -0
- package/dist/ports/model-endpoints.port.js +9 -0
- package/package.json +9 -9
package/README.md
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export { fromChatCompletion, makeCompatLanguageModel, toChatMessages, toChatTool
|
|
|
9
9
|
export type { CompatConfig } from "./llm/compat.js";
|
|
10
10
|
export { makeOpenAiCodexLanguageModel, OPENAI_CODEX_API_URL, toOpenAiCodexRequestBody } from "./llm/openAiCodex.js";
|
|
11
11
|
export { normalizeOpenAiCodexWebSocketEvent, openAiCodexUuidV7, OpenAiCodexWebSocketHttpClient } from "./llm/openAiCodexWebSocket.js";
|
|
12
|
-
export { buildProvider, OPENCODE_CHAT_URL, OPENCODE_RESPONSES_API_URL, prependClaudeCode, usesOpenCodeResponses, withAnthropicCacheBreakpoints, } from "./llm/providers.js";
|
|
12
|
+
export { buildProvider, chatCompletionsUrl, OPENCODE_CHAT_URL, OPENCODE_RESPONSES_API_URL, prependClaudeCode, usesOpenCodeResponses, withAnthropicCacheBreakpoints, } from "./llm/providers.js";
|
|
13
13
|
export { classifyLlmError, LLM_REQUEST_TIMEOUT_MS, MAX_HONORED_RETRY_AFTER_MS, rejectEmptyResponse, retryableLlm, } from "./llm/retry.js";
|
|
14
14
|
export type { ErrorClass } from "./llm/retry.js";
|
|
15
15
|
export { generateWith, LanguageModelLive, LanguageModelSelectionLive } from "./llm/router.js";
|
|
@@ -17,3 +17,4 @@ export { configuredModelCatalog, ConfiguredModelCatalogLive, reasoningEffortsFor
|
|
|
17
17
|
export type { ReasoningEffort } from "./llm/modelCatalog.js";
|
|
18
18
|
export { UtilityLlmLive } from "./llm/utilityLlm.js";
|
|
19
19
|
export { modelsPlugin, default } from "./plugin.adapter.js";
|
|
20
|
+
export { CurrentModelEndpoints, ModelEndpoint, ModelEndpoints } from "./ports/model-endpoints.port.js";
|
package/dist/index.js
CHANGED
|
@@ -30,6 +30,7 @@ export { makeOpenAiCodexLanguageModel, OPENAI_CODEX_API_URL, toOpenAiCodexReques
|
|
|
30
30
|
export { normalizeOpenAiCodexWebSocketEvent, openAiCodexUuidV7, OpenAiCodexWebSocketHttpClient } from "./llm/openAiCodexWebSocket.js";
|
|
31
31
|
export {
|
|
32
32
|
buildProvider,
|
|
33
|
+
chatCompletionsUrl,
|
|
33
34
|
OPENCODE_CHAT_URL,
|
|
34
35
|
OPENCODE_RESPONSES_API_URL,
|
|
35
36
|
prependClaudeCode,
|
|
@@ -51,3 +52,4 @@ export {
|
|
|
51
52
|
} from "./llm/modelCatalog.js";
|
|
52
53
|
export { UtilityLlmLive } from "./llm/utilityLlm.js";
|
|
53
54
|
export { modelsPlugin, default } from "./plugin.adapter.js";
|
|
55
|
+
export { CurrentModelEndpoints, ModelEndpoint, ModelEndpoints } from "./ports/model-endpoints.port.js";
|
package/dist/llm/compat.d.ts
CHANGED
|
@@ -19,8 +19,8 @@ export interface CompatConfig {
|
|
|
19
19
|
readonly moduleName: string;
|
|
20
20
|
/** Full chat-completions endpoint. */
|
|
21
21
|
readonly chatUrl: string;
|
|
22
|
-
/** Bearer key (already resolved
|
|
23
|
-
readonly apiKey
|
|
22
|
+
/** Bearer key (already resolved). Omit for keyless endpoints such as a local server. */
|
|
23
|
+
readonly apiKey?: string;
|
|
24
24
|
/** Provider-native model id. */
|
|
25
25
|
readonly model: string;
|
|
26
26
|
/** Host-selected thinking mode. Omit to retain family defaults. */
|
package/dist/llm/compat.js
CHANGED
|
@@ -142,7 +142,7 @@ const requestSettings = (config, cacheKey, policy) => ({
|
|
|
142
142
|
method: "POST",
|
|
143
143
|
headers: {
|
|
144
144
|
"content-type": "application/json",
|
|
145
|
-
authorization: `Bearer ${config.apiKey}`
|
|
145
|
+
...config.apiKey === void 0 || config.apiKey.length === 0 ? {} : { authorization: `Bearer ${config.apiKey}` }
|
|
146
146
|
},
|
|
147
147
|
body: JSON.stringify(body)
|
|
148
148
|
});
|
package/dist/llm/providers.d.ts
CHANGED
|
@@ -11,8 +11,9 @@ import type { Credential, ModelSelection } from "@xandreed/core";
|
|
|
11
11
|
*
|
|
12
12
|
* v1 providers: opencode (OpenAI-compatible gateway — the default), google
|
|
13
13
|
* (Gemini's OpenAI-compatible endpoint), anthropic (api key or subscription
|
|
14
|
-
* OAuth), openai (api key)
|
|
15
|
-
*
|
|
14
|
+
* OAuth), openai (api key), openai-codex (subscription OAuth). A configured
|
|
15
|
+
* endpoint, or a `local` credential with a `baseUrl`, sends its provider's
|
|
16
|
+
* models to that OpenAI-compatible URL, with or without a key.
|
|
16
17
|
*/
|
|
17
18
|
export declare const OPENCODE_CHAT_URL = "https://opencode.ai/zen/go/v1/chat/completions";
|
|
18
19
|
/** OpenCode serves GPT models through the OpenAI Responses protocol. */
|
|
@@ -37,5 +38,7 @@ export declare const prependClaudeCode: (options: unknown) => unknown;
|
|
|
37
38
|
* alone.
|
|
38
39
|
*/
|
|
39
40
|
export declare const withAnthropicCacheBreakpoints: (options: unknown) => unknown;
|
|
41
|
+
/** `<url>/chat/completions` of an OpenAI-compatible base URL. */
|
|
42
|
+
export declare const chatCompletionsUrl: (baseUrl: string) => string;
|
|
40
43
|
/** Preserve adapter descriptors and describe the public configuration of SDK-backed models. */
|
|
41
44
|
export declare const buildProvider: (selection: ModelSelection, credential: Credential | undefined, key: Redacted.Redacted<string> | undefined) => Effect.Effect<BuiltProvider, AuthError, HttpClient.HttpClient | Scope.Scope>;
|
package/dist/llm/providers.js
CHANGED
|
@@ -8,6 +8,7 @@ import { ANTHROPIC_OAUTH_BETA, CLAUDE_CODE_SYSTEM } from "../auth/anthropicOAuth
|
|
|
8
8
|
import { makeCompatLanguageModel } from "./compat.js";
|
|
9
9
|
import { makeOpenAiCodexLanguageModel } from "./openAiCodex.js";
|
|
10
10
|
import { openAiCodexAccountId } from "../auth/openAiCodexOAuth.js";
|
|
11
|
+
import { CurrentModelEndpoints } from "../ports/model-endpoints.port.js";
|
|
11
12
|
export const OPENCODE_CHAT_URL = "https://opencode.ai/zen/go/v1/chat/completions", OPENCODE_RESPONSES_API_URL = "https://opencode.ai/zen/v1", GOOGLE_CHAT_URL = "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions", usesOpenCodeResponses = (modelId) => /^gpt-/i.test(modelId);
|
|
12
13
|
const anthropicOAuthTransform = (access) => (client) => client.pipe(HttpClient.mapRequest((req) => req.pipe(HttpClientRequest.setHeaders({
|
|
13
14
|
Authorization: `Bearer ${Redacted.value(access)}`,
|
|
@@ -57,7 +58,22 @@ const missingKey = (selection) => new AuthError({
|
|
|
57
58
|
}
|
|
58
59
|
})
|
|
59
60
|
})
|
|
60
|
-
})
|
|
61
|
+
});
|
|
62
|
+
export const chatCompletionsUrl = (baseUrl) => `${baseUrl.replace(/\/+$/, "")}/chat/completions`;
|
|
63
|
+
const endpointKey = (endpoint, stored) => Option.fromNullishOr(endpoint.apiKey).pipe(Option.orElse(() => Option.flatMap(Option.fromNullishOr(endpoint.apiKeyEnv), (name) => Option.fromNullishOr(process.env[name]))), Option.orElse(() => Option.map(Option.fromNullishOr(stored), Redacted.value)), Option.filter((value) => value.length > 0)), endpointModel = (selection, url, key, standardOnly) => makeCompatLanguageModel({
|
|
64
|
+
moduleName: selection.provider,
|
|
65
|
+
chatUrl: chatCompletionsUrl(url),
|
|
66
|
+
model: selection.modelId,
|
|
67
|
+
standardOnly,
|
|
68
|
+
...Option.match(key, { onNone: () => ({}), onSome: (apiKey) => ({ apiKey }) })
|
|
69
|
+
}).pipe(Effect.map((svc) => ({ svc, prependClaudeCode: !1 }))), buildProviderService = (selection, credential, key) => Effect.flatMap(Effect.service(CurrentModelEndpoints), (endpoints) => {
|
|
70
|
+
const endpoint = Option.fromNullishOr(endpoints[selection.provider]);
|
|
71
|
+
if (Option.isSome(endpoint))
|
|
72
|
+
return endpointModel(selection, endpoint.value.url, endpointKey(endpoint.value, key), endpoint.value.standardOnly ?? !0);
|
|
73
|
+
if (credential?.type === "local" && credential.baseUrl !== void 0)
|
|
74
|
+
return endpointModel(selection, credential.baseUrl, Option.none(), !0);
|
|
75
|
+
return buildBuiltInProvider(selection, credential, key);
|
|
76
|
+
}), buildBuiltInProvider = (selection, credential, key) => {
|
|
61
77
|
const oauth = credential?.type === "oauth";
|
|
62
78
|
if (selection.provider === "opencode") {
|
|
63
79
|
if (key === void 0)
|
|
@@ -110,7 +126,7 @@ const missingKey = (selection) => new AuthError({
|
|
|
110
126
|
}).pipe(Effect.provideService(OpenAiClient.OpenAiClient, client))), Effect.map((svc) => ({ svc, prependClaudeCode: !1 }))));
|
|
111
127
|
return Effect.fail(new AuthError({
|
|
112
128
|
provider: selection.provider,
|
|
113
|
-
message: `provider "${selection.provider}" is not wired
|
|
129
|
+
message: `provider "${selection.provider}" is not wired (built in: opencode, google, anthropic, openai, openai-codex; add others as models plugin endpoints)`
|
|
114
130
|
}));
|
|
115
131
|
};
|
|
116
132
|
export const buildProvider = (selection, credential, key) => buildProviderService(selection, credential, key).pipe(Effect.flatMap((built) => Effect.gen(function* () {
|
package/dist/plugin.adapter.d.ts
CHANGED
|
@@ -5,10 +5,26 @@ export declare const modelsPlugin: import("@xandreed/core").TypedPlugin<{
|
|
|
5
5
|
readonly fastModel: string;
|
|
6
6
|
readonly fallbackModel: string;
|
|
7
7
|
readonly inheritPrevious: boolean;
|
|
8
|
+
readonly endpoints: {
|
|
9
|
+
readonly [x: string]: {
|
|
10
|
+
readonly url: string;
|
|
11
|
+
readonly apiKey?: string;
|
|
12
|
+
readonly apiKeyEnv?: string;
|
|
13
|
+
readonly standardOnly?: boolean;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
8
16
|
}, {
|
|
9
17
|
readonly model: string;
|
|
10
18
|
readonly fastModel: string;
|
|
11
19
|
readonly fallbackModel: string;
|
|
12
20
|
readonly inheritPrevious: boolean;
|
|
21
|
+
readonly endpoints: {
|
|
22
|
+
readonly [x: string]: {
|
|
23
|
+
readonly url: string;
|
|
24
|
+
readonly apiKey?: string;
|
|
25
|
+
readonly apiKeyEnv?: string;
|
|
26
|
+
readonly standardOnly?: boolean;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
13
29
|
}, SettingsStore | AuthStore | ModelCatalog | UtilityLlm | LanguageModel.LanguageModel, SettingsError, SessionEnvironment>;
|
|
14
30
|
export default modelsPlugin;
|
package/dist/plugin.adapter.js
CHANGED
|
@@ -7,12 +7,13 @@ import { LanguageModelLive } from "./llm/router.js";
|
|
|
7
7
|
import { UtilityLlmLive } from "./llm/utilityLlm.js";
|
|
8
8
|
import { ConfiguredModelCatalogLive } from "./llm/modelCatalog.js";
|
|
9
9
|
import { LocalSettingsStoreLive } from "./settings/localSettings.js";
|
|
10
|
-
|
|
10
|
+
import { CurrentModelEndpoints, ModelEndpoints } from "./ports/model-endpoints.port.js";
|
|
11
|
+
const Config = Schema.Struct({ model: Schema.String, fastModel: Schema.String, fallbackModel: Schema.String, inheritPrevious: Schema.Boolean, endpoints: ModelEndpoints });
|
|
11
12
|
export const modelsPlugin = definePlugin({
|
|
12
13
|
id: "@xandreed/plugin-models",
|
|
13
|
-
version: "0.
|
|
14
|
+
version: "0.13.0",
|
|
14
15
|
config: Config,
|
|
15
|
-
defaults: { model: "", fastModel: "", fallbackModel: "", inheritPrevious: !0 },
|
|
16
|
+
defaults: { model: "", fastModel: "", fallbackModel: "", inheritPrevious: !0, endpoints: {} },
|
|
16
17
|
requires: [SessionEnvironment],
|
|
17
18
|
provides: [LanguageModel.LanguageModel, UtilityLlm, AuthStore, SettingsStore, ModelCatalog],
|
|
18
19
|
layer: (config) => Layer.unwrap(Effect.gen(function* () {
|
|
@@ -20,7 +21,7 @@ export const modelsPlugin = definePlugin({
|
|
|
20
21
|
load: Effect.succeed(new EngineSettings({ ...previous, model: Option.orElse(optional(config.model), () => previous.model), fastModel: Option.orElse(optional(config.fastModel), () => previous.fastModel), fallbackModel: Option.orElse(optional(config.fallbackModel), () => previous.fallbackModel) })),
|
|
21
22
|
setRole: () => Effect.fail(new SettingsError({ message: "Edit the models plugin configuration to change a model" })),
|
|
22
23
|
set: () => Effect.fail(new SettingsError({ message: "Edit the models plugin configuration to change settings" }))
|
|
23
|
-
}), base = Layer.
|
|
24
|
+
}), base = Layer.mergeAll(settings, LocalAuthStoreLive(workspace, homedir(), ".efferent/runtime", config.inheritPrevious ? ".efferent" : void 0), Layer.succeed(CurrentModelEndpoints, config.endpoints));
|
|
24
25
|
return Layer.mergeAll(LanguageModelLive, UtilityLlmLive, ConfiguredModelCatalogLive).pipe(Layer.provideMerge(base));
|
|
25
26
|
}))
|
|
26
27
|
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Context, Schema } from "effect";
|
|
2
|
+
/**
|
|
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.
|
|
9
|
+
*/
|
|
10
|
+
export declare const ModelEndpoint: Schema.Struct<{
|
|
11
|
+
readonly url: Schema.String;
|
|
12
|
+
readonly apiKey: Schema.optionalKey<Schema.String>;
|
|
13
|
+
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<{
|
|
19
|
+
readonly url: Schema.String;
|
|
20
|
+
readonly apiKey: Schema.optionalKey<Schema.String>;
|
|
21
|
+
readonly apiKeyEnv: Schema.optionalKey<Schema.String>;
|
|
22
|
+
readonly standardOnly: Schema.optionalKey<Schema.Boolean>;
|
|
23
|
+
}>>;
|
|
24
|
+
export type ModelEndpoints = typeof ModelEndpoints.Type;
|
|
25
|
+
/** The endpoints the models plugin was configured with; none by default. */
|
|
26
|
+
export declare const CurrentModelEndpoints: Context.Reference<{
|
|
27
|
+
readonly [x: string]: {
|
|
28
|
+
readonly url: string;
|
|
29
|
+
readonly apiKey?: string;
|
|
30
|
+
readonly apiKeyEnv?: string;
|
|
31
|
+
readonly standardOnly?: boolean;
|
|
32
|
+
};
|
|
33
|
+
}>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Context, Schema } from "effect";
|
|
2
|
+
export const ModelEndpoint = Schema.Struct({
|
|
3
|
+
url: Schema.String,
|
|
4
|
+
apiKey: Schema.optionalKey(Schema.String),
|
|
5
|
+
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", {
|
|
8
|
+
defaultValue: () => ({})
|
|
9
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xandreed/plugin-models",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
|
+
"engines": {
|
|
5
|
+
"node": ">=24",
|
|
6
|
+
"bun": ">=1.3.0"
|
|
7
|
+
},
|
|
4
8
|
"type": "module",
|
|
5
9
|
"main": "./dist/index.js",
|
|
6
10
|
"exports": {
|
|
@@ -14,10 +18,10 @@
|
|
|
14
18
|
}
|
|
15
19
|
},
|
|
16
20
|
"dependencies": {
|
|
17
|
-
"@xandreed/core": "0.
|
|
18
|
-
"effect": "4.0.
|
|
19
|
-
"@effect/ai-anthropic": "4.0.
|
|
20
|
-
"@effect/ai-openai": "4.0.
|
|
21
|
+
"@xandreed/core": "0.13.0",
|
|
22
|
+
"effect": "4.0.7",
|
|
23
|
+
"@effect/ai-anthropic": "4.0.7",
|
|
24
|
+
"@effect/ai-openai": "4.0.7",
|
|
21
25
|
"ws": "^8.21.0"
|
|
22
26
|
},
|
|
23
27
|
"private": false,
|
|
@@ -29,9 +33,5 @@
|
|
|
29
33
|
"README.md",
|
|
30
34
|
"LICENSE"
|
|
31
35
|
],
|
|
32
|
-
"engines": {
|
|
33
|
-
"node": ">=24",
|
|
34
|
-
"bun": ">=1.3.0"
|
|
35
|
-
},
|
|
36
36
|
"license": "MIT"
|
|
37
37
|
}
|