feat: onboarding UX for the TUI (#8513)
This commit is contained in:
@@ -45,6 +45,11 @@
|
||||
"requestType": "ListProvidersRequest",
|
||||
"responseType": "ListProvidersResponse"
|
||||
},
|
||||
{
|
||||
"method": "_goose/providers/details",
|
||||
"requestType": "GetProviderDetailsRequest",
|
||||
"responseType": "GetProviderDetailsResponse"
|
||||
},
|
||||
{
|
||||
"method": "_goose/config/read",
|
||||
"requestType": "ReadConfigRequest",
|
||||
|
||||
@@ -261,6 +261,112 @@
|
||||
"label"
|
||||
]
|
||||
},
|
||||
"GetProviderDetailsRequest": {
|
||||
"type": "object",
|
||||
"description": "List providers with full metadata (config keys, setup steps, etc.).",
|
||||
"x-side": "agent",
|
||||
"x-method": "_goose/providers/details"
|
||||
},
|
||||
"GetProviderDetailsResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"providers": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/ProviderDetailEntry"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"providers"
|
||||
],
|
||||
"description": "Provider details response.",
|
||||
"x-side": "agent",
|
||||
"x-method": "_goose/providers/details"
|
||||
},
|
||||
"ProviderDetailEntry": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"displayName": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"defaultModel": {
|
||||
"type": "string"
|
||||
},
|
||||
"isConfigured": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"providerType": {
|
||||
"type": "string"
|
||||
},
|
||||
"configKeys": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/ProviderConfigKey"
|
||||
}
|
||||
},
|
||||
"setupSteps": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": []
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"displayName",
|
||||
"description",
|
||||
"defaultModel",
|
||||
"isConfigured",
|
||||
"providerType",
|
||||
"configKeys"
|
||||
]
|
||||
},
|
||||
"ProviderConfigKey": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"secret": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"default": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"oauthFlow": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"deviceCodeFlow": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"primary": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"required",
|
||||
"secret"
|
||||
]
|
||||
},
|
||||
"ReadConfigRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -568,6 +674,15 @@
|
||||
"description": "Params for _goose/providers/list",
|
||||
"title": "ListProvidersRequest"
|
||||
},
|
||||
{
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/$defs/GetProviderDetailsRequest"
|
||||
}
|
||||
],
|
||||
"description": "Params for _goose/providers/details",
|
||||
"title": "GetProviderDetailsRequest"
|
||||
},
|
||||
{
|
||||
"allOf": [
|
||||
{
|
||||
@@ -736,6 +851,14 @@
|
||||
],
|
||||
"title": "ListProvidersResponse"
|
||||
},
|
||||
{
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/$defs/GetProviderDetailsResponse"
|
||||
}
|
||||
],
|
||||
"title": "GetProviderDetailsResponse"
|
||||
},
|
||||
{
|
||||
"allOf": [
|
||||
{
|
||||
|
||||
@@ -2323,6 +2323,58 @@ impl GooseAcpAgent {
|
||||
})
|
||||
}
|
||||
|
||||
#[custom_method(GetProviderDetailsRequest)]
|
||||
async fn on_get_provider_details(
|
||||
&self,
|
||||
_req: GetProviderDetailsRequest,
|
||||
) -> Result<GetProviderDetailsResponse, sacp::Error> {
|
||||
let config = self.load_config().ok();
|
||||
let all = goose::providers::providers().await;
|
||||
let entries = all
|
||||
.into_iter()
|
||||
.map(|(metadata, provider_type)| {
|
||||
let is_configured = config
|
||||
.as_ref()
|
||||
.map(|c| {
|
||||
metadata.config_keys.iter().all(|k| {
|
||||
if !k.required {
|
||||
return true;
|
||||
}
|
||||
if k.secret {
|
||||
c.get_secret::<String>(&k.name).is_ok()
|
||||
} else {
|
||||
c.get_param::<String>(&k.name).is_ok()
|
||||
}
|
||||
})
|
||||
})
|
||||
.unwrap_or(false);
|
||||
ProviderDetailEntry {
|
||||
name: metadata.name.clone(),
|
||||
display_name: metadata.display_name.clone(),
|
||||
description: metadata.description.clone(),
|
||||
default_model: metadata.default_model.clone(),
|
||||
is_configured,
|
||||
provider_type: format!("{:?}", provider_type),
|
||||
config_keys: metadata
|
||||
.config_keys
|
||||
.iter()
|
||||
.map(|k| ProviderConfigKey {
|
||||
name: k.name.clone(),
|
||||
required: k.required,
|
||||
secret: k.secret,
|
||||
default: k.default.clone(),
|
||||
oauth_flow: k.oauth_flow,
|
||||
device_code_flow: k.device_code_flow,
|
||||
primary: k.primary,
|
||||
})
|
||||
.collect(),
|
||||
setup_steps: metadata.setup_steps.clone(),
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
Ok(GetProviderDetailsResponse { providers: entries })
|
||||
}
|
||||
|
||||
#[custom_method(ReadConfigRequest)]
|
||||
async fn on_read_config(
|
||||
&self,
|
||||
|
||||
@@ -254,6 +254,47 @@ pub struct ImportSessionResponse {
|
||||
pub message_count: u64,
|
||||
}
|
||||
|
||||
/// List providers with full metadata (config keys, setup steps, etc.).
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema, JsonRpcRequest)]
|
||||
#[request(method = "_goose/providers/details", response = GetProviderDetailsResponse)]
|
||||
pub struct GetProviderDetailsRequest {}
|
||||
|
||||
/// Provider details response.
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema, JsonRpcResponse)]
|
||||
pub struct GetProviderDetailsResponse {
|
||||
pub providers: Vec<ProviderDetailEntry>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ProviderDetailEntry {
|
||||
pub name: String,
|
||||
pub display_name: String,
|
||||
pub description: String,
|
||||
pub default_model: String,
|
||||
pub is_configured: bool,
|
||||
pub provider_type: String,
|
||||
pub config_keys: Vec<ProviderConfigKey>,
|
||||
#[serde(default)]
|
||||
pub setup_steps: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ProviderConfigKey {
|
||||
pub name: String,
|
||||
pub required: bool,
|
||||
pub secret: bool,
|
||||
#[serde(default)]
|
||||
pub default: Option<String>,
|
||||
#[serde(default)]
|
||||
pub oauth_flow: bool,
|
||||
#[serde(default)]
|
||||
pub device_code_flow: bool,
|
||||
#[serde(default)]
|
||||
pub primary: bool,
|
||||
}
|
||||
|
||||
/// Empty success response for operations that return no data.
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema, JsonRpcResponse)]
|
||||
pub struct EmptyResponse {}
|
||||
|
||||
Reference in New Issue
Block a user