feat(models): per-model probe testing with auto-detect UI (#133)

* feat(models): add per-model probe testing and auto-detect in UI

Move health probes from provider level to model level for precise
testing with real model_id and client_type. Provider test is now a
simple reachability check.

Backend:
- Add POST /models/:id/test endpoint that probes the model's provider
  using its actual model_id and client_type
- Add model healthcheck checker for bot health checks (chat/memory/embedding)
- Simplify provider test to reachability-only

Frontend:
- Auto-probe models on mount with status indicator (green/yellow/red dot + latency)
- Auto-probe provider reachability on load and on provider switch
- Fix missing faBolt icon registration
- Manual re-probe via refresh button

Closes #117

* fix(models): increase probe timeout to 15s for slow providers

Some providers (e.g. DashScope) exceed the 5s probe timeout, causing
false-negative "context deadline exceeded" errors. Increase per-probe
timeout to 15s and healthcheck overall timeout to 30s.

* fix(sdk): regenerate exports after merge conflict

Resolve duplicate SDK exports introduced by merge conflict resolution so the web build can compile again while preserving new model probe endpoints.
This commit is contained in:
BBQ
2026-03-02 14:59:15 +08:00
committed by GitHub
parent cfb5f660bc
commit f9f968f13f
21 changed files with 850 additions and 355 deletions
+80 -38
View File
@@ -5457,6 +5457,56 @@ const docTemplate = `{
}
}
},
"/models/{id}/test": {
"post": {
"description": "Probe a model's provider endpoint using the model's real model_id and client_type to verify configuration",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"models"
],
"summary": "Test model connectivity",
"parameters": [
{
"type": "string",
"description": "Model internal ID (UUID)",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/models.TestResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/handlers.ErrorResponse"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/handlers.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/handlers.ErrorResponse"
}
}
}
}
},
"/ping": {
"get": {
"tags": [
@@ -8984,6 +9034,36 @@ const docTemplate = `{
"ModelTypeEmbedding"
]
},
"models.TestResponse": {
"type": "object",
"properties": {
"latency_ms": {
"type": "integer"
},
"message": {
"type": "string"
},
"reachable": {
"type": "boolean"
},
"status": {
"$ref": "#/definitions/models.TestStatus"
}
}
},
"models.TestStatus": {
"type": "string",
"enum": [
"ok",
"auth_error",
"error"
],
"x-enum-varnames": [
"TestStatusOK",
"TestStatusAuthError",
"TestStatusError"
]
},
"models.UpdateRequest": {
"type": "object",
"properties": {
@@ -9016,38 +9096,6 @@ const docTemplate = `{
}
}
},
"providers.CheckResult": {
"type": "object",
"properties": {
"latency_ms": {
"type": "integer"
},
"message": {
"type": "string"
},
"status": {
"$ref": "#/definitions/providers.CheckStatus"
},
"status_code": {
"type": "integer"
}
}
},
"providers.CheckStatus": {
"type": "string",
"enum": [
"supported",
"auth_error",
"unsupported",
"error"
],
"x-enum-varnames": [
"CheckStatusSupported",
"CheckStatusAuthError",
"CheckStatusUnsupported",
"CheckStatusError"
]
},
"providers.CountResponse": {
"type": "object",
"properties": {
@@ -9109,12 +9157,6 @@ const docTemplate = `{
"providers.TestResponse": {
"type": "object",
"properties": {
"checks": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/providers.CheckResult"
}
},
"latency_ms": {
"type": "integer"
},