opencode-models-discovery 0.4.9 → 0.5.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/README.md +39 -2
- package/package.json +1 -1
- package/src/plugin/config-hook.ts +18 -9
- package/src/plugin/enhance-config.ts +29 -6
- package/src/plugin/event-hook.ts +4 -6
- package/src/plugin/index.ts +9 -7
- package/src/plugin/logger.ts +98 -0
- package/src/types/plugin-config.ts +43 -1
package/README.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# opencode-models-discovery
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/opencode-models-discovery)
|
|
4
|
+
[](https://www.npmjs.com/package/opencode-models-discovery)
|
|
5
|
+
|
|
3
6
|
> Forked from [opencode-lmstudio](https://github.com/nicktasios/opencode-lmstudio) and expanded to support **any OpenAI-compatible provider**.
|
|
4
7
|
|
|
5
8
|
OpenCode plugin for auto-discovery of OpenAI-compatible models with dynamic provider configuration.
|
|
@@ -66,6 +69,10 @@ The plugin configuration is placed in the `plugin` array using tuple format `["p
|
|
|
66
69
|
"include": [],
|
|
67
70
|
"exclude": []
|
|
68
71
|
},
|
|
72
|
+
"models": {
|
|
73
|
+
"includeRegex": [],
|
|
74
|
+
"excludeRegex": []
|
|
75
|
+
},
|
|
69
76
|
"discovery": {
|
|
70
77
|
"enabled": true,
|
|
71
78
|
"ttl": 15000
|
|
@@ -97,6 +104,30 @@ Control which providers are discovered:
|
|
|
97
104
|
}
|
|
98
105
|
```
|
|
99
106
|
|
|
107
|
+
#### Model Filtering
|
|
108
|
+
|
|
109
|
+
Control which discovered models are auto-injected with regular expressions:
|
|
110
|
+
|
|
111
|
+
| Option | Type | Description |
|
|
112
|
+
|--------|------|-------------|
|
|
113
|
+
| `models.includeRegex` | `string[]` | If non-empty, only discovered model IDs matching at least one regex will be added |
|
|
114
|
+
| `models.excludeRegex` | `string[]` | Discovered model IDs matching any regex will be skipped (only used when `includeRegex` is empty) |
|
|
115
|
+
|
|
116
|
+
Regex filtering only applies to auto-discovered models. Models already explicitly configured by the user are preserved.
|
|
117
|
+
|
|
118
|
+
```json
|
|
119
|
+
{
|
|
120
|
+
"plugin": [
|
|
121
|
+
["opencode-models-discovery", {
|
|
122
|
+
"models": {
|
|
123
|
+
"includeRegex": ["^qwen/", "gpt-4"],
|
|
124
|
+
"excludeRegex": ["embedding", "test"]
|
|
125
|
+
}
|
|
126
|
+
}]
|
|
127
|
+
]
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
100
131
|
### How It Works
|
|
101
132
|
|
|
102
133
|
1. On OpenCode startup, the plugin's `config` hook is called
|
|
@@ -119,7 +150,7 @@ The plugin supports any OpenAI-compatible provider. Here are the most common one
|
|
|
119
150
|
| **Text Generation WebUI** | 5000 | OpenAI-compatible extension | `@ai-sdk/openai-compatible` |
|
|
120
151
|
| **FastChat (Vicuna)** | 8001 | Multi-model serving | `@ai-sdk/openai-compatible` |
|
|
121
152
|
| **vLLM** | 8000 | High-performance inference | `@ai-sdk/openai-compatible` |
|
|
122
|
-
| **
|
|
153
|
+
| **CLIProxyAPI** | 8317 | A LLM proxy server | `@ai-sdk/anthropic` (with `/v1` backend) & `@ai-sdk/openai-compatible` |
|
|
123
154
|
|
|
124
155
|
#### Anthropic API with Custom Backend
|
|
125
156
|
|
|
@@ -203,10 +234,16 @@ This means providers using `@ai-sdk/anthropic` with OpenAI-compatible backends (
|
|
|
203
234
|
- At least one OpenAI-compatible provider running locally or remotely
|
|
204
235
|
- Provider server API accessible (e.g., `http://127.0.0.1:11434/v1`)
|
|
205
236
|
|
|
237
|
+
## Logging
|
|
238
|
+
|
|
239
|
+
When available, the plugin writes logs through OpenCode's structured server log API via `client.app.log(...)` using the service name `opencode-model-discovery`.
|
|
240
|
+
|
|
241
|
+
If structured logging is unavailable in the runtime, the plugin falls back to prefixed `console.*` output. Key log categories are emitted through metadata such as `plugin`, `config`, `discovery`, `event`, and `filtering` to make local debugging easier with `opencode --print-logs`.
|
|
242
|
+
|
|
206
243
|
## License
|
|
207
244
|
|
|
208
245
|
MIT
|
|
209
246
|
|
|
210
247
|
## Contributing
|
|
211
248
|
|
|
212
|
-
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
249
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "opencode-models-discovery",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.5.3",
|
|
5
5
|
"description": "OpenCode plugin for auto-discovery of OpenAI-compatible models with dynamic provider configuration",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./src/index.ts",
|
|
@@ -1,38 +1,45 @@
|
|
|
1
1
|
import { ToastNotifier } from '../ui/toast-notifier'
|
|
2
2
|
import { validateConfig } from '../utils/validation'
|
|
3
3
|
import { enhanceConfig } from './enhance-config'
|
|
4
|
+
import type { PluginLogger } from './logger'
|
|
4
5
|
import type { PluginInput } from '@opencode-ai/plugin'
|
|
5
6
|
import type { PluginConfig } from '../types/plugin-config'
|
|
6
7
|
|
|
7
8
|
export function createConfigHook(
|
|
8
9
|
client: PluginInput['client'],
|
|
9
10
|
toastNotifier: ToastNotifier,
|
|
10
|
-
pluginConfig: PluginConfig
|
|
11
|
+
pluginConfig: PluginConfig,
|
|
12
|
+
logger: PluginLogger
|
|
11
13
|
) {
|
|
12
14
|
return async (config: any) => {
|
|
13
15
|
if (config && (Object.isFrozen?.(config) || Object.isSealed?.(config))) {
|
|
14
|
-
|
|
16
|
+
logger.warn('Config object is frozen or sealed; cannot modify directly')
|
|
15
17
|
return
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
const validation = validateConfig(config)
|
|
19
21
|
if (!validation.isValid) {
|
|
20
|
-
|
|
22
|
+
logger.error('Invalid config provided', { errors: validation.errors })
|
|
21
23
|
toastNotifier.error("Plugin configuration is invalid", "Configuration Error").catch(() => {})
|
|
22
24
|
return
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
if (validation.warnings.length > 0) {
|
|
26
|
-
|
|
28
|
+
logger.warn('Config warnings', { warnings: validation.warnings })
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
if (pluginConfig.discovery?.enabled === false) {
|
|
30
|
-
|
|
32
|
+
logger.info('Discovery disabled by configuration')
|
|
31
33
|
return
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
+
const discoveryPromise = enhanceConfig(
|
|
37
|
+
config,
|
|
38
|
+
client,
|
|
39
|
+
toastNotifier,
|
|
40
|
+
pluginConfig,
|
|
41
|
+
logger.child({ category: 'discovery' })
|
|
42
|
+
)
|
|
36
43
|
const timeoutMs = 5000
|
|
37
44
|
|
|
38
45
|
try {
|
|
@@ -43,7 +50,9 @@ export function createConfigHook(
|
|
|
43
50
|
})
|
|
44
51
|
])
|
|
45
52
|
} catch (error) {
|
|
46
|
-
|
|
53
|
+
logger.error('Config enhancement failed', {
|
|
54
|
+
error: error instanceof Error ? error.message : String(error),
|
|
55
|
+
})
|
|
47
56
|
}
|
|
48
57
|
}
|
|
49
|
-
}
|
|
58
|
+
}
|
|
@@ -2,7 +2,8 @@ import { ModelStatusCache } from '../cache/model-status-cache'
|
|
|
2
2
|
import { ToastNotifier } from '../ui/toast-notifier'
|
|
3
3
|
import { categorizeModel, formatModelName, extractModelOwner } from '../utils'
|
|
4
4
|
import { normalizeBaseURL, checkProviderHealth, discoverModelsFromProvider, autoDetectOpenAICompatibleProvider, canDiscoverModels } from '../utils/openai-compatible-api'
|
|
5
|
-
import { getProviderFilter, getDiscoveryConfig, shouldDiscoverProvider } from '../types/plugin-config'
|
|
5
|
+
import { getProviderFilter, getDiscoveryConfig, getModelRegexFilter, shouldDiscoverModel, shouldDiscoverProvider } from '../types/plugin-config'
|
|
6
|
+
import type { PluginLogger } from './logger'
|
|
6
7
|
import type { PluginInput } from '@opencode-ai/plugin'
|
|
7
8
|
import type { OpenAIModel } from '../types'
|
|
8
9
|
import type { PluginConfig } from '../types/plugin-config'
|
|
@@ -19,7 +20,8 @@ export async function enhanceConfig(
|
|
|
19
20
|
config: any,
|
|
20
21
|
client: PluginInput['client'],
|
|
21
22
|
toastNotifier: ToastNotifier,
|
|
22
|
-
pluginConfig: PluginConfig
|
|
23
|
+
pluginConfig: PluginConfig,
|
|
24
|
+
logger: PluginLogger
|
|
23
25
|
): Promise<void> {
|
|
24
26
|
modelStatusCache.invalidateAll()
|
|
25
27
|
|
|
@@ -27,6 +29,7 @@ export async function enhanceConfig(
|
|
|
27
29
|
const providers = config.provider || {}
|
|
28
30
|
const openAICompatibleProviders: DiscoveredProvider[] = []
|
|
29
31
|
const providerFilter = getProviderFilter(pluginConfig)
|
|
32
|
+
const modelRegexFilter = getModelRegexFilter(pluginConfig, logger.child({ category: 'filtering' }))
|
|
30
33
|
const discoveryConfig = getDiscoveryConfig(pluginConfig)
|
|
31
34
|
|
|
32
35
|
for (const [providerName, providerConfig] of Object.entries(providers)) {
|
|
@@ -61,6 +64,11 @@ export async function enhanceConfig(
|
|
|
61
64
|
try {
|
|
62
65
|
models = await discoverModelsFromProvider(baseURL, apiKey)
|
|
63
66
|
} catch (error) {
|
|
67
|
+
logger.warn('Provider model discovery failed', {
|
|
68
|
+
provider: providerName,
|
|
69
|
+
baseURL,
|
|
70
|
+
error: error instanceof Error ? error.message : String(error),
|
|
71
|
+
})
|
|
64
72
|
continue
|
|
65
73
|
}
|
|
66
74
|
|
|
@@ -77,6 +85,10 @@ export async function enhanceConfig(
|
|
|
77
85
|
const modelKey = model.id
|
|
78
86
|
|
|
79
87
|
if (!existingModels[modelKey]) {
|
|
88
|
+
if (!shouldDiscoverModel(model.id, modelRegexFilter)) {
|
|
89
|
+
continue
|
|
90
|
+
}
|
|
91
|
+
|
|
80
92
|
const modelType = categorizeModel(model.id)
|
|
81
93
|
const owner = extractModelOwner(model.id)
|
|
82
94
|
const modelConfig: any = {
|
|
@@ -126,13 +138,19 @@ export async function enhanceConfig(
|
|
|
126
138
|
|
|
127
139
|
if (openAICompatibleProviders.length > 0) {
|
|
128
140
|
const totalModels = openAICompatibleProviders.reduce((sum, p) => sum + Object.keys(p.models).length, 0)
|
|
129
|
-
|
|
141
|
+
logger.info('Provider model discovery completed', {
|
|
142
|
+
providerCount: openAICompatibleProviders.length,
|
|
143
|
+
modelCount: totalModels,
|
|
144
|
+
})
|
|
130
145
|
}
|
|
131
146
|
|
|
132
147
|
if (Object.keys(providers).length === 0) {
|
|
133
148
|
const detected = await autoDetectOpenAICompatibleProvider()
|
|
134
149
|
if (detected) {
|
|
135
|
-
|
|
150
|
+
logger.info('Detected OpenAI-compatible provider but found no configured providers', {
|
|
151
|
+
provider: detected.name,
|
|
152
|
+
baseURL: detected.baseURL,
|
|
153
|
+
})
|
|
136
154
|
}
|
|
137
155
|
}
|
|
138
156
|
|
|
@@ -155,9 +173,14 @@ export async function enhanceConfig(
|
|
|
155
173
|
}
|
|
156
174
|
}
|
|
157
175
|
} catch (error) {
|
|
176
|
+
logger.warn('Model status cache refresh failed', {
|
|
177
|
+
error: error instanceof Error ? error.message : String(error),
|
|
178
|
+
})
|
|
158
179
|
}
|
|
159
180
|
} catch (error) {
|
|
160
|
-
|
|
181
|
+
logger.error('Unexpected error in enhanceConfig', {
|
|
182
|
+
error: error instanceof Error ? error.message : String(error),
|
|
183
|
+
})
|
|
161
184
|
toastNotifier.warning("Plugin configuration failed", "Configuration Error").catch(() => {})
|
|
162
185
|
}
|
|
163
|
-
}
|
|
186
|
+
}
|
package/src/plugin/event-hook.ts
CHANGED
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
import { validateHookInput } from '../utils/validation'
|
|
2
|
+
import type { PluginLogger } from './logger'
|
|
2
3
|
|
|
3
|
-
export function createEventHook() {
|
|
4
|
+
export function createEventHook(logger: PluginLogger) {
|
|
4
5
|
return async ({ event }: { event: any }) => {
|
|
5
|
-
// Validate event input
|
|
6
6
|
const validation = validateHookInput('event', { event })
|
|
7
7
|
if (!validation.isValid) {
|
|
8
|
-
|
|
8
|
+
logger.error('Invalid event input', { errors: validation.errors })
|
|
9
9
|
return
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
// Monitor for session events to provide LM Studio status
|
|
13
12
|
if (event.type === "session.created" || event.type === "session.updated") {
|
|
14
|
-
//
|
|
13
|
+
// Reserved for future session-aware discovery diagnostics.
|
|
15
14
|
}
|
|
16
15
|
}
|
|
17
16
|
}
|
|
18
|
-
|
package/src/plugin/index.ts
CHANGED
|
@@ -3,15 +3,15 @@ import { ToastNotifier } from '../ui/toast-notifier'
|
|
|
3
3
|
import { createConfigHook } from './config-hook'
|
|
4
4
|
import { createEventHook } from './event-hook'
|
|
5
5
|
import { createChatParamsHook } from './chat-params-hook'
|
|
6
|
+
import { createPluginLogger } from './logger'
|
|
6
7
|
import { parsePluginConfig, type PluginConfig } from '../types/plugin-config'
|
|
7
8
|
|
|
8
9
|
export const ModelDiscoveryPlugin: Plugin = async (input: PluginInput, options?: PluginOptions) => {
|
|
9
|
-
console.log("[opencode-model-discovery] Model discovery plugin initialized")
|
|
10
|
-
|
|
11
10
|
const { client } = input
|
|
11
|
+
const logger = createPluginLogger(client, { category: 'plugin' })
|
|
12
12
|
|
|
13
13
|
if (!client || typeof client !== 'object') {
|
|
14
|
-
|
|
14
|
+
logger.error('Invalid client provided to plugin')
|
|
15
15
|
return {
|
|
16
16
|
config: async () => {},
|
|
17
17
|
event: async () => {},
|
|
@@ -19,19 +19,21 @@ export const ModelDiscoveryPlugin: Plugin = async (input: PluginInput, options?:
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
logger.info('Model discovery plugin initialized')
|
|
23
|
+
|
|
22
24
|
const pluginConfig: PluginConfig = parsePluginConfig(options || {})
|
|
23
25
|
|
|
24
26
|
if (pluginConfig.discovery?.enabled === false) {
|
|
25
|
-
|
|
27
|
+
logger.info('Discovery disabled by configuration', { category: 'config' })
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
const toastNotifier = new ToastNotifier(client)
|
|
29
31
|
|
|
30
32
|
return {
|
|
31
|
-
config: createConfigHook(client, toastNotifier, pluginConfig),
|
|
32
|
-
event: createEventHook(),
|
|
33
|
+
config: createConfigHook(client, toastNotifier, pluginConfig, logger.child({ category: 'config' })),
|
|
34
|
+
event: createEventHook(logger.child({ category: 'event' })),
|
|
33
35
|
"chat.params": createChatParamsHook(toastNotifier, pluginConfig),
|
|
34
36
|
}
|
|
35
37
|
}
|
|
36
38
|
|
|
37
|
-
export const LMStudioPlugin = ModelDiscoveryPlugin
|
|
39
|
+
export const LMStudioPlugin = ModelDiscoveryPlugin
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { PluginInput } from '@opencode-ai/plugin'
|
|
2
|
+
|
|
3
|
+
const SERVICE_NAME = 'opencode-models-discovery'
|
|
4
|
+
|
|
5
|
+
type LogLevel = 'debug' | 'info' | 'warn' | 'error'
|
|
6
|
+
|
|
7
|
+
type LogExtra = Record<string, unknown>
|
|
8
|
+
|
|
9
|
+
type PluginClient = PluginInput['client'] | null | undefined
|
|
10
|
+
|
|
11
|
+
export interface PluginLogger {
|
|
12
|
+
debug(message: string, extra?: LogExtra): void
|
|
13
|
+
info(message: string, extra?: LogExtra): void
|
|
14
|
+
warn(message: string, extra?: LogExtra): void
|
|
15
|
+
error(message: string, extra?: LogExtra): void
|
|
16
|
+
child(extra: LogExtra): PluginLogger
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function getConsoleMethod(level: LogLevel): typeof console.log {
|
|
20
|
+
if (level === 'error') {
|
|
21
|
+
return console.error
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (level === 'warn') {
|
|
25
|
+
return console.warn
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (level === 'debug') {
|
|
29
|
+
return console.debug
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return console.info
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function mergeExtra(baseExtra: LogExtra, extra?: LogExtra): LogExtra | undefined {
|
|
36
|
+
const merged = {
|
|
37
|
+
...baseExtra,
|
|
38
|
+
...extra,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return Object.keys(merged).length > 0 ? merged : undefined
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function fallbackToConsole(level: LogLevel, message: string, extra?: LogExtra) {
|
|
45
|
+
const log = getConsoleMethod(level)
|
|
46
|
+
const prefix = `[${SERVICE_NAME}] ${message}`
|
|
47
|
+
|
|
48
|
+
if (extra && Object.keys(extra).length > 0) {
|
|
49
|
+
log(prefix, extra)
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
log(prefix)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function createPluginLogger(client?: PluginClient, baseExtra: LogExtra = {}): PluginLogger {
|
|
57
|
+
const log = (level: LogLevel, message: string, extra?: LogExtra) => {
|
|
58
|
+
const mergedExtra = mergeExtra(baseExtra, extra)
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
if (client?.app?.log) {
|
|
62
|
+
void client.app.log({
|
|
63
|
+
body: {
|
|
64
|
+
service: SERVICE_NAME,
|
|
65
|
+
level,
|
|
66
|
+
message,
|
|
67
|
+
extra: mergedExtra,
|
|
68
|
+
},
|
|
69
|
+
}).catch(() => {
|
|
70
|
+
fallbackToConsole(level, message, mergedExtra)
|
|
71
|
+
})
|
|
72
|
+
return
|
|
73
|
+
}
|
|
74
|
+
} catch {
|
|
75
|
+
// Fall back to console logging when structured logging is unavailable.
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
fallbackToConsole(level, message, mergedExtra)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
debug(message, extra) {
|
|
83
|
+
log('debug', message, extra)
|
|
84
|
+
},
|
|
85
|
+
info(message, extra) {
|
|
86
|
+
log('info', message, extra)
|
|
87
|
+
},
|
|
88
|
+
warn(message, extra) {
|
|
89
|
+
log('warn', message, extra)
|
|
90
|
+
},
|
|
91
|
+
error(message, extra) {
|
|
92
|
+
log('error', message, extra)
|
|
93
|
+
},
|
|
94
|
+
child(extra) {
|
|
95
|
+
return createPluginLogger(client, mergeExtra(baseExtra, extra) || {})
|
|
96
|
+
},
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -3,6 +3,10 @@ export interface PluginConfig {
|
|
|
3
3
|
include?: string[]
|
|
4
4
|
exclude?: string[]
|
|
5
5
|
}
|
|
6
|
+
models?: {
|
|
7
|
+
includeRegex?: string[]
|
|
8
|
+
excludeRegex?: string[]
|
|
9
|
+
}
|
|
6
10
|
discovery?: {
|
|
7
11
|
enabled?: boolean
|
|
8
12
|
ttl?: number
|
|
@@ -19,6 +23,11 @@ export interface DiscoveryConfig {
|
|
|
19
23
|
ttl: number
|
|
20
24
|
}
|
|
21
25
|
|
|
26
|
+
export interface ModelRegexFilter {
|
|
27
|
+
includeRegex: RegExp[]
|
|
28
|
+
excludeRegex: RegExp[]
|
|
29
|
+
}
|
|
30
|
+
|
|
22
31
|
export const DEFAULT_DISCOVERY_CONFIG: DiscoveryConfig = {
|
|
23
32
|
enabled: true,
|
|
24
33
|
ttl: 15000,
|
|
@@ -48,6 +57,38 @@ export function getDiscoveryConfig(config: PluginConfig): DiscoveryConfig {
|
|
|
48
57
|
}
|
|
49
58
|
}
|
|
50
59
|
|
|
60
|
+
function toRegExp(pattern: string, logger?: PluginLogger): RegExp | null {
|
|
61
|
+
try {
|
|
62
|
+
return new RegExp(pattern)
|
|
63
|
+
} catch {
|
|
64
|
+
if (logger) {
|
|
65
|
+
logger.warn('Ignoring invalid model regex', { category: 'filtering', pattern })
|
|
66
|
+
} else {
|
|
67
|
+
console.warn(`[opencode-model-discovery] Ignoring invalid model regex: ${pattern}`)
|
|
68
|
+
}
|
|
69
|
+
return null
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function getModelRegexFilter(config: PluginConfig, logger?: PluginLogger): ModelRegexFilter {
|
|
74
|
+
return {
|
|
75
|
+
includeRegex: (config.models?.includeRegex || []).map((pattern) => toRegExp(pattern, logger)).filter((pattern): pattern is RegExp => pattern !== null),
|
|
76
|
+
excludeRegex: (config.models?.excludeRegex || []).map((pattern) => toRegExp(pattern, logger)).filter((pattern): pattern is RegExp => pattern !== null),
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function shouldDiscoverModel(modelId: string, filter: ModelRegexFilter): boolean {
|
|
81
|
+
if (filter.includeRegex.length > 0) {
|
|
82
|
+
return filter.includeRegex.some((pattern) => pattern.test(modelId))
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (filter.excludeRegex.length > 0) {
|
|
86
|
+
return !filter.excludeRegex.some((pattern) => pattern.test(modelId))
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return true
|
|
90
|
+
}
|
|
91
|
+
|
|
51
92
|
export function parsePluginConfig(rawConfig: any): PluginConfig {
|
|
52
93
|
if (!rawConfig) {
|
|
53
94
|
return {}
|
|
@@ -68,4 +109,5 @@ export function parsePluginConfig(rawConfig: any): PluginConfig {
|
|
|
68
109
|
}
|
|
69
110
|
|
|
70
111
|
return {}
|
|
71
|
-
}
|
|
112
|
+
}
|
|
113
|
+
import type { PluginLogger } from '../plugin/logger'
|