@vymalo/opencode-models-info 0.11.0 → 0.14.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 +25 -1
- package/dist/cache.d.ts +23 -23
- package/dist/cache.js +89 -91
- package/dist/cache.js.map +1 -1
- package/dist/config.d.ts +23 -23
- package/dist/config.js +109 -108
- package/dist/config.js.map +1 -1
- package/dist/fetcher.d.ts +9 -9
- package/dist/fetcher.js +76 -70
- package/dist/fetcher.js.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lib.js +1 -0
- package/dist/lib.js.map +1 -1
- package/dist/logging.d.ts +6 -6
- package/dist/logging.js +58 -62
- package/dist/logging.js.map +1 -1
- package/dist/mapping.d.ts +39 -39
- package/dist/mapping.js +144 -130
- package/dist/mapping.js.map +1 -1
- package/dist/opencode.d.ts +4 -4
- package/dist/opencode.js +70 -69
- package/dist/opencode.js.map +1 -1
- package/dist/plugin.d.ts +25 -25
- package/dist/plugin.js +342 -311
- package/dist/plugin.js.map +1 -1
- package/dist/scheduler.d.ts +16 -16
- package/dist/scheduler.js +55 -57
- package/dist/scheduler.js.map +1 -1
- package/dist/types.d.ts +67 -54
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -1
- package/package.json +3 -3
package/dist/mapping.js
CHANGED
|
@@ -1,152 +1,166 @@
|
|
|
1
|
-
const OPENCODE_MODALITIES = new Set([
|
|
1
|
+
const OPENCODE_MODALITIES = new Set([
|
|
2
|
+
"text",
|
|
3
|
+
"audio",
|
|
4
|
+
"image",
|
|
5
|
+
"video",
|
|
6
|
+
"pdf"
|
|
7
|
+
]);
|
|
2
8
|
/**
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
9
|
+
* Pure transformation from an OpenRouter model entry to the subset of
|
|
10
|
+
* OpenCode `ModelConfig` fields we know how to populate. Returns only the
|
|
11
|
+
* fields we can derive; callers do the upstream-wins merge.
|
|
12
|
+
*/
|
|
7
13
|
export function mapOpenRouterEntry(entry, overwrite) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
14
|
+
const out = {};
|
|
15
|
+
if (entry.name) {
|
|
16
|
+
out.name = entry.name;
|
|
17
|
+
}
|
|
18
|
+
const context = entry.top_provider?.context_length ?? entry.context_length;
|
|
19
|
+
const output = entry.top_provider?.max_completion_tokens;
|
|
20
|
+
if (typeof context === "number" && typeof output === "number") {
|
|
21
|
+
out.limit = {
|
|
22
|
+
context,
|
|
23
|
+
output
|
|
24
|
+
};
|
|
25
|
+
} else if (typeof context === "number") {}
|
|
26
|
+
const cost = mapPricing(entry.pricing);
|
|
27
|
+
if (cost) {
|
|
28
|
+
out.cost = cost;
|
|
29
|
+
}
|
|
30
|
+
const inputMods = filterModalities(entry.architecture?.input_modalities);
|
|
31
|
+
const outputMods = filterModalities(entry.architecture?.output_modalities);
|
|
32
|
+
if (inputMods.length > 0 && outputMods.length > 0) {
|
|
33
|
+
out.modalities = {
|
|
34
|
+
input: inputMods,
|
|
35
|
+
output: outputMods
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
const params = entry.supported_parameters ?? [];
|
|
39
|
+
const paramSet = new Set(params.map((p) => p.toLowerCase()));
|
|
40
|
+
// We can only *assert a capability false* when the source actually told us
|
|
41
|
+
// about it. An absent `supported_parameters` / `input_modalities` means "we
|
|
42
|
+
// don't know" — never a misleading `false`.
|
|
43
|
+
const knowsParams = Array.isArray(entry.supported_parameters);
|
|
44
|
+
const knowsInputMods = Array.isArray(entry.architecture?.input_modalities);
|
|
45
|
+
setCapability(out, "tool_call", paramSet.has("tools") || paramSet.has("tool_choice"), {
|
|
46
|
+
known: knowsParams,
|
|
47
|
+
overwrite
|
|
48
|
+
});
|
|
49
|
+
setCapability(out, "reasoning", paramSet.has("reasoning") || paramSet.has("reasoning_effort") || paramSet.has("thinking"), {
|
|
50
|
+
known: knowsParams,
|
|
51
|
+
overwrite
|
|
52
|
+
});
|
|
53
|
+
setCapability(out, "temperature", paramSet.has("temperature"), {
|
|
54
|
+
known: knowsParams,
|
|
55
|
+
overwrite
|
|
56
|
+
});
|
|
57
|
+
setCapability(out, "attachment", inputMods.some((m) => m !== "text"), {
|
|
58
|
+
known: knowsInputMods,
|
|
59
|
+
overwrite
|
|
60
|
+
});
|
|
61
|
+
return out;
|
|
50
62
|
}
|
|
51
63
|
/**
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
64
|
+
* Emit a capability flag. By default these are *true-only*: an absent
|
|
65
|
+
* capability stays `undefined`, which under upstream-wins correctly means
|
|
66
|
+
* "leave whatever is there". But a field opted into `overwrite` wants the
|
|
67
|
+
* endpoint's answer to win outright — so we must also emit an explicit `false`
|
|
68
|
+
* to clear a stale `true` another plugin stamped. We only do that when the
|
|
69
|
+
* source actually carried the relevant data (`known`); otherwise there is
|
|
70
|
+
* nothing to assert and the field stays `undefined`.
|
|
71
|
+
*/
|
|
60
72
|
function setCapability(out, field, present, opts) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
73
|
+
if (present) {
|
|
74
|
+
out[field] = true;
|
|
75
|
+
} else if (opts.known && opts.overwrite?.has(field)) {
|
|
76
|
+
out[field] = false;
|
|
77
|
+
}
|
|
67
78
|
}
|
|
68
79
|
function mapPricing(pricing) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
80
|
+
if (!pricing) {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
const input = perMillion(pricing.prompt);
|
|
84
|
+
const output = perMillion(pricing.completion);
|
|
85
|
+
if (input === undefined || output === undefined) {
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
const cost = {
|
|
89
|
+
input,
|
|
90
|
+
output
|
|
91
|
+
};
|
|
92
|
+
const cacheRead = perMillion(pricing.input_cache_read);
|
|
93
|
+
if (cacheRead !== undefined) {
|
|
94
|
+
cost.cache_read = cacheRead;
|
|
95
|
+
}
|
|
96
|
+
const cacheWrite = perMillion(pricing.input_cache_write);
|
|
97
|
+
if (cacheWrite !== undefined) {
|
|
98
|
+
cost.cache_write = cacheWrite;
|
|
99
|
+
}
|
|
100
|
+
return cost;
|
|
87
101
|
}
|
|
88
102
|
/** OpenRouter pricing is a string per-token in USD; OpenCode stores per-1M-token. */
|
|
89
103
|
function perMillion(raw) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
104
|
+
if (raw === undefined || raw === null || raw === "") {
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
const parsed = Number.parseFloat(raw);
|
|
108
|
+
if (!Number.isFinite(parsed)) {
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
return roundTo(parsed * 1e6, 6);
|
|
98
112
|
}
|
|
99
113
|
function roundTo(value, decimals) {
|
|
100
|
-
|
|
101
|
-
|
|
114
|
+
const factor = 10 ** decimals;
|
|
115
|
+
return Math.round(value * factor) / factor;
|
|
102
116
|
}
|
|
103
117
|
/**
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
118
|
+
* A model is "text-only" when the source reported modalities and both input
|
|
119
|
+
* and output are exactly `["text"]` — no vision/audio/video/pdf on either
|
|
120
|
+
* side. Undefined `modalities` means the source never told us, so we can't
|
|
121
|
+
* claim text-only (consistent with the true-only / "known" pattern above).
|
|
122
|
+
*/
|
|
109
123
|
export function isTextOnlyModality(modalities) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
124
|
+
if (!modalities) {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
const isTextOnlyList = (mods) => mods.length === 1 && mods[0] === "text";
|
|
128
|
+
return isTextOnlyList(modalities.input) && isTextOnlyList(modalities.output);
|
|
115
129
|
}
|
|
116
130
|
function filterModalities(values) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
return out;
|
|
131
|
+
if (!values) {
|
|
132
|
+
return [];
|
|
133
|
+
}
|
|
134
|
+
const out = [];
|
|
135
|
+
for (const value of values) {
|
|
136
|
+
if (OPENCODE_MODALITIES.has(value) && !out.includes(value)) {
|
|
137
|
+
out.push(value);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return out;
|
|
128
141
|
}
|
|
129
142
|
/**
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
143
|
+
* Merge a derived metadata snapshot onto an existing OpenCode model entry.
|
|
144
|
+
* Upstream wins by default: any field already present is left untouched.
|
|
145
|
+
* Returns the same object reference (mutated) for ergonomic chaining.
|
|
146
|
+
*
|
|
147
|
+
* `overwrite` opts specific fields *out* of upstream-wins, letting the derived
|
|
148
|
+
* (endpoint) value replace one that's already set. This exists because another
|
|
149
|
+
* plugin (e.g. `@vymalo/opencode-oauth2`) may auto-stamp a field such as `name`
|
|
150
|
+
* before this hook runs — to upstream-wins that looks like deliberate user
|
|
151
|
+
* config, so without an opt-out the endpoint's value can never land. A field
|
|
152
|
+
* named in `overwrite` only wins when the derived value is actually present.
|
|
153
|
+
*/
|
|
141
154
|
export function mergeIntoModel(existing, derived, overwrite) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
155
|
+
for (const [key, value] of Object.entries(derived)) {
|
|
156
|
+
if (value === undefined) {
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
if (existing[key] === undefined || overwrite?.has(key)) {
|
|
160
|
+
existing[key] = value;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return existing;
|
|
151
164
|
}
|
|
165
|
+
|
|
152
166
|
//# sourceMappingURL=mapping.js.map
|
package/dist/mapping.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"
|
|
1
|
+
{"mappings":"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","names":[],"sources":["../src/mapping.ts"],"version":3,"file":"mapping.js","sourceRoot":""}
|
package/dist/opencode.d.ts
CHANGED
|
@@ -2,10 +2,10 @@ import type { Plugin } from "@opencode-ai/plugin";
|
|
|
2
2
|
import { type CacheStore } from "./cache.js";
|
|
3
3
|
import { type Logger } from "./logging.js";
|
|
4
4
|
export interface OpenCodePluginFactoryOptions {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
logger?: Logger;
|
|
6
|
+
fetchImpl?: typeof fetch;
|
|
7
|
+
cache?: CacheStore;
|
|
8
|
+
cacheDir?: string;
|
|
9
9
|
}
|
|
10
10
|
export declare function createOpencodeModelsInfoPlugin(factoryOptions?: OpenCodePluginFactoryOptions): Plugin;
|
|
11
11
|
export declare const OpencodeModelsInfoPlugin: Plugin;
|
package/dist/opencode.js
CHANGED
|
@@ -3,79 +3,80 @@ import { createJsonConsoleLogger, DEFAULT_LOG_LEVEL, fromOpenCodeLogLevel, LOG_L
|
|
|
3
3
|
import { enrichConfig, startCacheRefreshSchedulers } from "./plugin.js";
|
|
4
4
|
const PLUGIN_SERVICE_NAME = "opencode-models-info-plugin";
|
|
5
5
|
/**
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
* Pipe plugin logs through OpenCode's `client.app.log` so they show up in the
|
|
7
|
+
* host's structured log stream, with the JSON console as a reliable fallback.
|
|
8
|
+
* Mirrors the pattern used by `@vymalo/opencode-oauth2`.
|
|
9
|
+
*/
|
|
10
10
|
function createOpenCodeLogger(client, getMinLevel) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
info: (event, fields) => write("info", event, fields),
|
|
45
|
-
warn: (event, fields) => write("warn", event, fields),
|
|
46
|
-
error: (event, fields) => write("error", event, fields)
|
|
47
|
-
};
|
|
11
|
+
const fallback = createJsonConsoleLogger("debug");
|
|
12
|
+
// OpenCode already captures plugin logs via client.app.log (and filters them
|
|
13
|
+
// by its own log level). Mirroring every event to stdout on top of that just
|
|
14
|
+
// floods the terminal, so only mirror warn/error to the JSON console by
|
|
15
|
+
// default; set VYMALO_PLUGIN_CONSOLE_LOG=1 to restore full console output.
|
|
16
|
+
const consoleAll = /^(1|true|yes|on)$/i.test(process.env.VYMALO_PLUGIN_CONSOLE_LOG ?? "");
|
|
17
|
+
const write = (level, event, fields) => {
|
|
18
|
+
if (LOG_LEVEL_PRIORITY[level] < LOG_LEVEL_PRIORITY[getMinLevel()]) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (consoleAll || level === "warn" || level === "error") {
|
|
22
|
+
fallback[level](event, fields);
|
|
23
|
+
}
|
|
24
|
+
// OpenCode's log API has no `trace` tier — fold it into the host's most
|
|
25
|
+
// verbose level (`debug`) for the wire payload; our own `getMinLevel()`
|
|
26
|
+
// gate above is what actually unlocks trace events.
|
|
27
|
+
const hostLevel = level === "trace" ? "debug" : level;
|
|
28
|
+
void client.app.log({ body: {
|
|
29
|
+
service: PLUGIN_SERVICE_NAME,
|
|
30
|
+
level: hostLevel,
|
|
31
|
+
message: event,
|
|
32
|
+
extra: fields
|
|
33
|
+
} }).catch(() => {
|
|
34
|
+
/* best-effort */
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
return {
|
|
38
|
+
trace: (event, fields) => write("trace", event, fields),
|
|
39
|
+
debug: (event, fields) => write("debug", event, fields),
|
|
40
|
+
info: (event, fields) => write("info", event, fields),
|
|
41
|
+
warn: (event, fields) => write("warn", event, fields),
|
|
42
|
+
error: (event, fields) => write("error", event, fields)
|
|
43
|
+
};
|
|
48
44
|
}
|
|
49
45
|
export function createOpencodeModelsInfoPlugin(factoryOptions = {}) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
46
|
+
return async ({ client }) => {
|
|
47
|
+
let currentLogLevel = DEFAULT_LOG_LEVEL;
|
|
48
|
+
const logger = factoryOptions.logger ?? createOpenCodeLogger(client, () => currentLogLevel);
|
|
49
|
+
const cache = factoryOptions.cache ?? new FileCacheStore(factoryOptions.cacheDir);
|
|
50
|
+
let schedulers = [];
|
|
51
|
+
const stopSchedulers = () => {
|
|
52
|
+
for (const handle of schedulers) {
|
|
53
|
+
handle.stop();
|
|
54
|
+
}
|
|
55
|
+
schedulers = [];
|
|
56
|
+
};
|
|
57
|
+
return {
|
|
58
|
+
config: async (config) => {
|
|
59
|
+
currentLogLevel = fromOpenCodeLogLevel(config.logLevel) ?? DEFAULT_LOG_LEVEL;
|
|
60
|
+
const deps = {
|
|
61
|
+
cache,
|
|
62
|
+
logger,
|
|
63
|
+
fetchImpl: factoryOptions.fetchImpl
|
|
64
|
+
};
|
|
65
|
+
await enrichConfig(config, deps);
|
|
66
|
+
// OpenCode re-runs `config` on certain config edits — stop the
|
|
67
|
+
// schedulers from any prior run before starting fresh ones so a
|
|
68
|
+
// rebuilt config never leaks a duplicate background timer per
|
|
69
|
+
// provider.
|
|
70
|
+
stopSchedulers();
|
|
71
|
+
schedulers = startCacheRefreshSchedulers(config, deps);
|
|
72
|
+
},
|
|
73
|
+
dispose: async () => {
|
|
74
|
+
stopSchedulers();
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
78
|
}
|
|
79
79
|
export const OpencodeModelsInfoPlugin = createOpencodeModelsInfoPlugin();
|
|
80
80
|
export default OpencodeModelsInfoPlugin;
|
|
81
|
+
|
|
81
82
|
//# sourceMappingURL=opencode.js.map
|
package/dist/opencode.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"
|
|
1
|
+
{"mappings":"AAEA,SAA0B,sBAAsB;AAChD,SACE,yBACA,mBACA,sBAEA,0BAGK;AACP,SAAiC,cAAc,mCAAmC;AAGlF,MAAM,sBAAsB;;;;;;AAgB5B,SAAS,qBAAqB,QAA+B,aAAqC;CAChG,MAAM,WAAW,wBAAwB,OAAO;;;;;CAKhD,MAAM,aAAa,qBAAqB,KAAK,QAAQ,IAAI,6BAA6B,EAAE;CAExF,MAAM,SAAS,OAAiB,OAAe,WAAuB;EACpE,IAAI,mBAAmB,SAAS,mBAAmB,YAAY,IAAI;GACjE;EACF;EACA,IAAI,cAAc,UAAU,UAAU,UAAU,SAAS;GACvD,SAAS,MAAM,CAAC,OAAO,MAAM;EAC/B;;;;EAIA,MAAM,YAAY,UAAU,UAAU,UAAU;EAChD,KAAK,OAAO,IACT,IAAI,EACH,MAAM;GACJ,SAAS;GACT,OAAO;GACP,SAAS;GACT,OAAO;EACT,EACF,CAAC,CAAC,CACD,YAAY;;EAEb,CAAC;CACL;CAEA,OAAO;EACL,QAAQ,OAAO,WAAW,MAAM,SAAS,OAAO,MAAM;EACtD,QAAQ,OAAO,WAAW,MAAM,SAAS,OAAO,MAAM;EACtD,OAAO,OAAO,WAAW,MAAM,QAAQ,OAAO,MAAM;EACpD,OAAO,OAAO,WAAW,MAAM,QAAQ,OAAO,MAAM;EACpD,QAAQ,OAAO,WAAW,MAAM,SAAS,OAAO,MAAM;CACxD;AACF;AAEA,OAAO,SAAS,+BACd,iBAA+C,CAAC,GACxC;CACR,OAAO,OAAO,EAAE,aAAa;EAC3B,IAAI,kBAA4B;EAChC,MAAM,SAAS,eAAe,UAAU,qBAAqB,cAAc,eAAe;EAC1F,MAAM,QAAQ,eAAe,SAAS,IAAI,eAAe,eAAe,QAAQ;EAChF,IAAI,aAAgC,CAAC;EAErC,MAAM,uBAA6B;GACjC,KAAK,MAAM,UAAU,YAAY;IAC/B,OAAO,KAAK;GACd;GACA,aAAa,CAAC;EAChB;EAEA,OAAO;GACL,QAAQ,OAAO,WAA2B;IACxC,kBAAkB,qBAAqB,OAAO,QAAQ,KAAK;IAC3D,MAAM,OAAO;KAAE;KAAO;KAAQ,WAAW,eAAe;IAAU;IAClE,MAAM,aAAa,QAA6B,IAAI;;;;;IAMpD,eAAe;IACf,aAAa,4BAA4B,QAA6B,IAAI;GAC5E;GACA,SAAS,YAAY;IACnB,eAAe;GACjB;EACF;CACF;AACF;AAEA,OAAO,MAAM,2BAAmC,+BAA+B;AAE/E,eAAe","names":[],"sources":["../src/opencode.ts"],"version":3,"file":"opencode.js","sourceRoot":""}
|
package/dist/plugin.d.ts
CHANGED
|
@@ -3,38 +3,38 @@ import type { Logger } from "./logging.js";
|
|
|
3
3
|
import { type SchedulerHandle } from "./scheduler.js";
|
|
4
4
|
export type ProviderOptions = Record<string, unknown> | undefined;
|
|
5
5
|
export interface ProviderConfigLike {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
options?: Record<string, unknown>;
|
|
7
|
+
models?: Record<string, Record<string, unknown>>;
|
|
8
8
|
}
|
|
9
9
|
export interface EnrichConfigInput {
|
|
10
|
-
|
|
10
|
+
provider?: Record<string, ProviderConfigLike>;
|
|
11
11
|
}
|
|
12
12
|
export interface EnrichDeps {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
cache: CacheStore;
|
|
14
|
+
logger: Logger;
|
|
15
|
+
fetchImpl?: typeof fetch;
|
|
16
|
+
now?: () => number;
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
* Walk every provider in the assembled OpenCode config, fetch its
|
|
20
|
+
* `meta.modelsInfoUrl` (if any) — honoring the cache — and merge derived
|
|
21
|
+
* metadata onto each matching model entry. Runs providers in parallel; one
|
|
22
|
+
* failure never blocks others.
|
|
23
|
+
*/
|
|
24
24
|
export declare function enrichConfig(input: EnrichConfigInput, deps: EnrichDeps): Promise<void>;
|
|
25
25
|
/**
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
26
|
+
* Start one background refresh scheduler per opted-in provider, keeping the
|
|
27
|
+
* on-disk cache warm at `meta.modelsInfoTtlSeconds` cadence (the same knob
|
|
28
|
+
* that already governs cache freshness — no separate interval to configure).
|
|
29
|
+
*
|
|
30
|
+
* `config` only runs at plugin load and on rare config-signature changes
|
|
31
|
+
* (see docs/models-info.md#periodic-refresh), so a long-lived OpenCode
|
|
32
|
+
* process would otherwise keep serving whatever the catalog looked like at
|
|
33
|
+
* boot until it happens to restart. This closes that gap for the *next*
|
|
34
|
+
* `config` run — it cannot push a live update into an already-open session,
|
|
35
|
+
* since a config hook has no way to hot-patch a running one. Callers own the
|
|
36
|
+
* returned handles' lifecycle: stop them when the config that produced them
|
|
37
|
+
* is superseded (a rebuilt `config` hook) or the plugin is disposed.
|
|
38
|
+
*/
|
|
39
39
|
export declare function startCacheRefreshSchedulers(input: EnrichConfigInput, deps: EnrichDeps): SchedulerHandle[];
|
|
40
40
|
export { FileCacheStore };
|