@staticeng/opencode-litellm 0.1.0 → 0.1.1
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/dist/index.d.ts +1 -1
- package/dist/index.js +3 -1
- package/dist/litellm.d.ts +1 -2
- package/dist/litellm.js +2 -9
- package/dist/mapping.d.ts +16 -2
- package/dist/mapping.js +103 -1
- package/dist/types.d.ts +3 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export declare const LiteLLMPlugin: (ctx: PluginInput, options?: LiteLLMPluginOp
|
|
|
4
4
|
config: (cfg: Config) => Promise<void>;
|
|
5
5
|
}>;
|
|
6
6
|
export default LiteLLMPlugin;
|
|
7
|
-
export { buildProvider, mapModels } from "./mapping.js";
|
|
7
|
+
export { buildProvider, mapModels, normalizeModelListResponse, modelListResponseShape, LiteLLMModelListResponseError } from "./mapping.js";
|
|
8
8
|
export { fetchModelInfo } from "./litellm.js";
|
|
9
9
|
export { deepMerge } from "./merge.js";
|
|
10
10
|
export type { LiteLLMPluginOptions, LiteLLMModelInfo, OpenCodeProvider, OpenCodeModel } from "./types.js";
|
package/dist/index.js
CHANGED
|
@@ -21,9 +21,11 @@ export const LiteLLMPlugin = async (ctx, options) => {
|
|
|
21
21
|
});
|
|
22
22
|
}
|
|
23
23
|
catch (error) {
|
|
24
|
+
const errorShape = error instanceof Error && "responseShape" in error ? error.responseShape : undefined;
|
|
24
25
|
await log(ctx, resolved.strict ? "error" : "warn", "failed to load LiteLLM provider metadata", {
|
|
25
26
|
providerKey: resolved.providerKey,
|
|
26
27
|
error: error instanceof Error ? error.message : String(error),
|
|
28
|
+
...(errorShape ? { responseShape: errorShape } : {}),
|
|
27
29
|
});
|
|
28
30
|
if (resolved.strict)
|
|
29
31
|
throw error;
|
|
@@ -32,6 +34,6 @@ export const LiteLLMPlugin = async (ctx, options) => {
|
|
|
32
34
|
};
|
|
33
35
|
};
|
|
34
36
|
export default LiteLLMPlugin;
|
|
35
|
-
export { buildProvider, mapModels } from "./mapping.js";
|
|
37
|
+
export { buildProvider, mapModels, normalizeModelListResponse, modelListResponseShape, LiteLLMModelListResponseError } from "./mapping.js";
|
|
36
38
|
export { fetchModelInfo } from "./litellm.js";
|
|
37
39
|
export { deepMerge } from "./merge.js";
|
package/dist/litellm.d.ts
CHANGED
|
@@ -1,3 +1,2 @@
|
|
|
1
1
|
import { type ResolvedOptions } from "./options.js";
|
|
2
|
-
|
|
3
|
-
export declare function fetchModelInfo(options: ResolvedOptions, fetchImpl?: typeof fetch): Promise<LiteLLMModelInfo[]>;
|
|
2
|
+
export declare function fetchModelInfo(options: ResolvedOptions, fetchImpl?: typeof fetch): Promise<import("./types.js").LiteLLMModelInfo[]>;
|
package/dist/litellm.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
+
import { normalizeModelListResponse } from "./mapping.js";
|
|
1
2
|
import { modelInfoURL } from "./options.js";
|
|
2
|
-
function isModelInfoArray(value) {
|
|
3
|
-
return Array.isArray(value);
|
|
4
|
-
}
|
|
5
3
|
export async function fetchModelInfo(options, fetchImpl = fetch) {
|
|
6
4
|
if (!options.baseURL)
|
|
7
5
|
throw new Error("opencode-litellm requires options.baseURL or LITELLM_BASE_URL");
|
|
@@ -20,12 +18,7 @@ export async function fetchModelInfo(options, fetchImpl = fetch) {
|
|
|
20
18
|
});
|
|
21
19
|
if (!response.ok)
|
|
22
20
|
throw new Error(`LiteLLM /model/info returned HTTP ${response.status}`);
|
|
23
|
-
|
|
24
|
-
if (isModelInfoArray(body))
|
|
25
|
-
return body;
|
|
26
|
-
if (isModelInfoArray(body.data))
|
|
27
|
-
return body.data;
|
|
28
|
-
throw new Error("LiteLLM /model/info response did not contain a data array");
|
|
21
|
+
return normalizeModelListResponse(await response.json());
|
|
29
22
|
}
|
|
30
23
|
finally {
|
|
31
24
|
clearTimeout(timeout);
|
package/dist/mapping.d.ts
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
import type { LiteLLMModelInfo, LiteLLMPluginOptions, OpenCodeModel, OpenCodeProvider } from "./types.js";
|
|
2
|
-
export
|
|
2
|
+
export type ModelListResponseShape = {
|
|
3
|
+
type: string;
|
|
4
|
+
length?: number;
|
|
5
|
+
keyCount?: number;
|
|
6
|
+
arrayFields?: string[];
|
|
7
|
+
objectValueCount?: number;
|
|
8
|
+
scalarValueCount?: number;
|
|
9
|
+
};
|
|
10
|
+
export declare function modelListResponseShape(value: unknown): ModelListResponseShape;
|
|
11
|
+
export declare class LiteLLMModelListResponseError extends Error {
|
|
12
|
+
responseShape: ModelListResponseShape;
|
|
13
|
+
constructor(response: unknown);
|
|
14
|
+
}
|
|
15
|
+
export declare function normalizeModelListResponse(response: unknown): LiteLLMModelInfo[];
|
|
16
|
+
export declare function mapModels(response: unknown, options?: LiteLLMPluginOptions): {
|
|
3
17
|
[k: string]: OpenCodeModel;
|
|
4
18
|
};
|
|
5
|
-
export declare function buildProvider(models:
|
|
19
|
+
export declare function buildProvider(models: unknown, options?: LiteLLMPluginOptions): OpenCodeProvider;
|
package/dist/mapping.js
CHANGED
|
@@ -2,6 +2,54 @@ import { deepMerge } from "./merge.js";
|
|
|
2
2
|
const DEFAULT_MODES = new Set(["chat", "responses"]);
|
|
3
3
|
const NON_CHAT_MODES = new Set(["embedding", "rerank"]);
|
|
4
4
|
const TEXT_MODALITY = "text";
|
|
5
|
+
const TEXT_ONLY_MODELS = new Set(["minimax-m2.7", "minimax_m2.7"]);
|
|
6
|
+
const MODEL_LIST_RESPONSE_ERROR_MESSAGE = "LiteLLM model list response did not contain a model array";
|
|
7
|
+
const MODEL_ARRAY_FIELDS = ["data", "models", "model_info"];
|
|
8
|
+
const MODEL_INFO_FIELDS = new Set([
|
|
9
|
+
"id",
|
|
10
|
+
"base_model",
|
|
11
|
+
"mode",
|
|
12
|
+
"input_cost_per_token",
|
|
13
|
+
"output_cost_per_token",
|
|
14
|
+
"max_tokens",
|
|
15
|
+
"max_input_tokens",
|
|
16
|
+
"max_output_tokens",
|
|
17
|
+
"supports_function_calling",
|
|
18
|
+
"supports_tool_choice",
|
|
19
|
+
"supports_vision",
|
|
20
|
+
"supports_pdf_input",
|
|
21
|
+
"supports_reasoning",
|
|
22
|
+
"supported_modalities",
|
|
23
|
+
"output_modalities",
|
|
24
|
+
"supported_params",
|
|
25
|
+
]);
|
|
26
|
+
function isRecord(value) {
|
|
27
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
28
|
+
}
|
|
29
|
+
export function modelListResponseShape(value) {
|
|
30
|
+
if (Array.isArray(value))
|
|
31
|
+
return { type: "array", length: value.length };
|
|
32
|
+
if (value === null)
|
|
33
|
+
return { type: "null" };
|
|
34
|
+
if (!isRecord(value))
|
|
35
|
+
return { type: typeof value };
|
|
36
|
+
const values = Object.values(value);
|
|
37
|
+
return {
|
|
38
|
+
type: "object",
|
|
39
|
+
keyCount: Object.keys(value).length,
|
|
40
|
+
arrayFields: MODEL_ARRAY_FIELDS.filter((field) => Array.isArray(value[field])),
|
|
41
|
+
objectValueCount: values.filter(isRecord).length,
|
|
42
|
+
scalarValueCount: values.filter((entry) => !isRecord(entry) && !Array.isArray(entry)).length,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export class LiteLLMModelListResponseError extends Error {
|
|
46
|
+
responseShape;
|
|
47
|
+
constructor(response) {
|
|
48
|
+
super(MODEL_LIST_RESPONSE_ERROR_MESSAGE);
|
|
49
|
+
this.name = "LiteLLMModelListResponseError";
|
|
50
|
+
this.responseShape = modelListResponseShape(response);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
5
53
|
function asString(value) {
|
|
6
54
|
return typeof value === "string" && value.trim() ? value : undefined;
|
|
7
55
|
}
|
|
@@ -19,6 +67,44 @@ function unique(values) {
|
|
|
19
67
|
function modelName(model) {
|
|
20
68
|
return asString(model.model_name) ?? asString(model.litellm_params?.model) ?? asString(model.model_info?.id);
|
|
21
69
|
}
|
|
70
|
+
function hasModelInfoFields(value) {
|
|
71
|
+
return Object.keys(value).some((key) => MODEL_INFO_FIELDS.has(key));
|
|
72
|
+
}
|
|
73
|
+
function isPlausibleMappedModel(value) {
|
|
74
|
+
if (isRecord(value.model_info) && hasModelInfoFields(value.model_info))
|
|
75
|
+
return true;
|
|
76
|
+
if (isRecord(value.litellm_params) && typeof value.litellm_params.model === "string")
|
|
77
|
+
return true;
|
|
78
|
+
return hasModelInfoFields(value);
|
|
79
|
+
}
|
|
80
|
+
function normalizeMappedModel(name, value) {
|
|
81
|
+
if (!isRecord(value))
|
|
82
|
+
return undefined;
|
|
83
|
+
const model = value;
|
|
84
|
+
if (modelName(model))
|
|
85
|
+
return model;
|
|
86
|
+
if (!isPlausibleMappedModel(value))
|
|
87
|
+
return undefined;
|
|
88
|
+
return { ...model, model_name: name };
|
|
89
|
+
}
|
|
90
|
+
export function normalizeModelListResponse(response) {
|
|
91
|
+
if (Array.isArray(response))
|
|
92
|
+
return response;
|
|
93
|
+
if (isRecord(response)) {
|
|
94
|
+
for (const field of MODEL_ARRAY_FIELDS) {
|
|
95
|
+
if (Array.isArray(response[field]))
|
|
96
|
+
return response[field];
|
|
97
|
+
}
|
|
98
|
+
if (MODEL_ARRAY_FIELDS.some((field) => field in response))
|
|
99
|
+
throw new LiteLLMModelListResponseError(response);
|
|
100
|
+
const mappedModels = Object.entries(response)
|
|
101
|
+
.map(([name, value]) => normalizeMappedModel(name, value))
|
|
102
|
+
.filter((model) => Boolean(model));
|
|
103
|
+
if (mappedModels.length > 0)
|
|
104
|
+
return mappedModels;
|
|
105
|
+
}
|
|
106
|
+
throw new LiteLLMModelListResponseError(response);
|
|
107
|
+
}
|
|
22
108
|
function mode(model) {
|
|
23
109
|
return asString(model.model_info?.mode) ?? "chat";
|
|
24
110
|
}
|
|
@@ -62,7 +148,22 @@ function limit(model) {
|
|
|
62
148
|
output,
|
|
63
149
|
};
|
|
64
150
|
}
|
|
151
|
+
function canonicalModelName(model) {
|
|
152
|
+
const name = modelName(model);
|
|
153
|
+
const base = asString(model.model_info?.base_model);
|
|
154
|
+
const id = asString(model.model_info?.id);
|
|
155
|
+
return [name, base, id].filter((value) => Boolean(value)).map((value) => value.toLowerCase());
|
|
156
|
+
}
|
|
157
|
+
function isTextOnlyModel(model) {
|
|
158
|
+
return canonicalModelName(model).some((name) => TEXT_ONLY_MODELS.has(name));
|
|
159
|
+
}
|
|
65
160
|
function modalities(model) {
|
|
161
|
+
if (isTextOnlyModel(model)) {
|
|
162
|
+
return {
|
|
163
|
+
input: [TEXT_MODALITY],
|
|
164
|
+
output: [TEXT_MODALITY],
|
|
165
|
+
};
|
|
166
|
+
}
|
|
66
167
|
return {
|
|
67
168
|
input: unique([
|
|
68
169
|
TEXT_MODALITY,
|
|
@@ -95,7 +196,8 @@ function generatedModel(model) {
|
|
|
95
196
|
...(model.model_info?.supports_function_calling || model.model_info?.supports_tool_choice ? { tool_call: true } : {}),
|
|
96
197
|
};
|
|
97
198
|
}
|
|
98
|
-
export function mapModels(
|
|
199
|
+
export function mapModels(response, options = {}) {
|
|
200
|
+
const models = normalizeModelListResponse(response);
|
|
99
201
|
return Object.fromEntries(models
|
|
100
202
|
.filter((model) => allowedByFilters(model, options))
|
|
101
203
|
.map((model) => {
|
package/dist/types.d.ts
CHANGED
|
@@ -69,8 +69,10 @@ export type LiteLLMModelInfo = JsonObject & {
|
|
|
69
69
|
supported_params?: string[];
|
|
70
70
|
};
|
|
71
71
|
};
|
|
72
|
-
export type LiteLLMModelInfoResponse = {
|
|
72
|
+
export type LiteLLMModelInfoResponse = LiteLLMModelInfo[] | {
|
|
73
73
|
data?: LiteLLMModelInfo[];
|
|
74
|
+
models?: LiteLLMModelInfo[];
|
|
75
|
+
model_info?: LiteLLMModelInfo[];
|
|
74
76
|
};
|
|
75
77
|
export type OpenCodeConfig = {
|
|
76
78
|
provider?: Record<string, OpenCodeProvider>;
|