created custom methods for agent mention and slash command (#9980)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
use agent_client_protocol::schema::{ContentBlock, McpServer, SessionInfo};
|
||||
use agent_client_protocol::schema::{AvailableCommand, ContentBlock, McpServer, SessionInfo};
|
||||
use agent_client_protocol::{JsonRpcRequest, JsonRpcResponse};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -1134,6 +1134,58 @@ pub struct ListSourcesResponse {
|
||||
pub sources: Vec<SourceEntry>,
|
||||
}
|
||||
|
||||
/// A user-facing `@` mention target backed by an agent, recipe, or subrecipe source.
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AgentMention {
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
pub source_type: SourceType,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub source_path: Option<String>,
|
||||
pub mention: String,
|
||||
}
|
||||
|
||||
/// List user-facing agent mention targets for `@` autocomplete.
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema, JsonRpcRequest)]
|
||||
#[request(
|
||||
method = "_goose/unstable/agent-mentions/list",
|
||||
response = ListAgentMentionsResponse
|
||||
)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ListAgentMentionsRequest {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub cwd: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub session_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema, JsonRpcResponse)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ListAgentMentionsResponse {
|
||||
pub agents: Vec<AgentMention>,
|
||||
}
|
||||
|
||||
/// List slash commands available for `/` autocomplete.
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema, JsonRpcRequest)]
|
||||
#[request(
|
||||
method = "_goose/unstable/slash-commands/list",
|
||||
response = ListSlashCommandsResponse
|
||||
)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ListSlashCommandsRequest {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub cwd: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub session_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema, JsonRpcResponse)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ListSlashCommandsResponse {
|
||||
pub available_commands: Vec<AvailableCommand>,
|
||||
}
|
||||
|
||||
/// Update an existing source's name, description, and content by absolute path.
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema, JsonRpcRequest)]
|
||||
#[request(method = "_goose/unstable/sources/update", response = UpdateSourceResponse)]
|
||||
|
||||
@@ -290,6 +290,16 @@
|
||||
"requestType": "ListSourcesRequest_unstable",
|
||||
"responseType": "ListSourcesResponse_unstable"
|
||||
},
|
||||
{
|
||||
"method": "_goose/unstable/agent-mentions/list",
|
||||
"requestType": "ListAgentMentionsRequest_unstable",
|
||||
"responseType": "ListAgentMentionsResponse_unstable"
|
||||
},
|
||||
{
|
||||
"method": "_goose/unstable/slash-commands/list",
|
||||
"requestType": "ListSlashCommandsRequest_unstable",
|
||||
"responseType": "ListSlashCommandsResponse_unstable"
|
||||
},
|
||||
{
|
||||
"method": "_goose/unstable/sources/update",
|
||||
"requestType": "UpdateSourceRequest_unstable",
|
||||
|
||||
@@ -3887,6 +3887,175 @@
|
||||
"x-side": "agent",
|
||||
"x-method": "_goose/unstable/sources/list"
|
||||
},
|
||||
"ListAgentMentionsRequest_unstable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"cwd": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"sessionId": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"description": "List user-facing agent mention targets for `@` autocomplete.",
|
||||
"x-side": "agent",
|
||||
"x-method": "_goose/unstable/agent-mentions/list"
|
||||
},
|
||||
"ListAgentMentionsResponse_unstable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"agents": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/AgentMention"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"agents"
|
||||
],
|
||||
"x-side": "agent",
|
||||
"x-method": "_goose/unstable/agent-mentions/list"
|
||||
},
|
||||
"AgentMention": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"sourceType": {
|
||||
"$ref": "#/$defs/SourceType"
|
||||
},
|
||||
"sourcePath": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"mention": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"description",
|
||||
"sourceType",
|
||||
"mention"
|
||||
],
|
||||
"description": "A user-facing `@` mention target backed by an agent, recipe, or subrecipe source."
|
||||
},
|
||||
"ListSlashCommandsRequest_unstable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"cwd": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"sessionId": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"description": "List slash commands available for `/` autocomplete.",
|
||||
"x-side": "agent",
|
||||
"x-method": "_goose/unstable/slash-commands/list"
|
||||
},
|
||||
"ListSlashCommandsResponse_unstable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"availableCommands": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/AvailableCommand"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"availableCommands"
|
||||
],
|
||||
"x-side": "agent",
|
||||
"x-method": "_goose/unstable/slash-commands/list"
|
||||
},
|
||||
"AvailableCommand": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Command name (e.g., `create_plan`, `research_codebase`)."
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Human-readable description of what the command does."
|
||||
},
|
||||
"input": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/$defs/AvailableCommandInput"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Input for the command if required"
|
||||
},
|
||||
"_meta": {
|
||||
"type": [
|
||||
"object",
|
||||
"null"
|
||||
],
|
||||
"additionalProperties": {},
|
||||
"description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"description": "Information about a command."
|
||||
},
|
||||
"AvailableCommandInput": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/$defs/UnstructuredCommandInput",
|
||||
"description": "All text that was typed after the command name is provided as input."
|
||||
}
|
||||
],
|
||||
"description": "The input specification for a command."
|
||||
},
|
||||
"UnstructuredCommandInput": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"hint": {
|
||||
"type": "string",
|
||||
"description": "A hint to display when the input hasn't been provided yet"
|
||||
},
|
||||
"_meta": {
|
||||
"type": [
|
||||
"object",
|
||||
"null"
|
||||
],
|
||||
"additionalProperties": {},
|
||||
"description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"hint"
|
||||
],
|
||||
"description": "All text that was typed after the command name is provided as input."
|
||||
},
|
||||
"UpdateSourceRequest_unstable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -5098,6 +5267,24 @@
|
||||
"description": "Params for _goose/unstable/sources/list",
|
||||
"title": "ListSourcesRequest_unstable"
|
||||
},
|
||||
{
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/$defs/ListAgentMentionsRequest_unstable"
|
||||
}
|
||||
],
|
||||
"description": "Params for _goose/unstable/agent-mentions/list",
|
||||
"title": "ListAgentMentionsRequest_unstable"
|
||||
},
|
||||
{
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/$defs/ListSlashCommandsRequest_unstable"
|
||||
}
|
||||
],
|
||||
"description": "Params for _goose/unstable/slash-commands/list",
|
||||
"title": "ListSlashCommandsRequest_unstable"
|
||||
},
|
||||
{
|
||||
"allOf": [
|
||||
{
|
||||
@@ -5558,6 +5745,22 @@
|
||||
],
|
||||
"title": "ListSourcesResponse_unstable"
|
||||
},
|
||||
{
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/$defs/ListAgentMentionsResponse_unstable"
|
||||
}
|
||||
],
|
||||
"title": "ListAgentMentionsResponse_unstable"
|
||||
},
|
||||
{
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/$defs/ListSlashCommandsResponse_unstable"
|
||||
}
|
||||
],
|
||||
"title": "ListSlashCommandsResponse_unstable"
|
||||
},
|
||||
{
|
||||
"allOf": [
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::agents::ExtensionLoadResult;
|
||||
use crate::config::{Config, GooseMode};
|
||||
use crate::providers::inventory::{ProviderInventoryEntry, ProviderInventoryService};
|
||||
use crate::session::Session;
|
||||
use crate::slash_commands::types::{SlashCommandEntry, SlashCommandSource};
|
||||
use agent_client_protocol::schema::{
|
||||
AvailableCommand, AvailableCommandInput, AvailableCommandsUpdate, ModelId, ModelInfo,
|
||||
SessionConfigOption, SessionConfigOptionCategory, SessionConfigSelectOption, SessionId,
|
||||
@@ -329,21 +330,54 @@ fn current_thinking_effort_value(model_config: &ModelConfig) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
fn available_commands_update(working_dir: &std::path::Path) -> AvailableCommandsUpdate {
|
||||
let commands = crate::slash_commands::slash_command::list_acp_commands(Some(working_dir))
|
||||
.into_iter()
|
||||
.map(|entry| {
|
||||
let mut command = AvailableCommand::new(entry.name, entry.description);
|
||||
if let Some(input_hint) = entry.input_hint {
|
||||
command = command.input(AvailableCommandInput::Unstructured(
|
||||
UnstructuredCommandInput::new(input_hint),
|
||||
));
|
||||
}
|
||||
command
|
||||
})
|
||||
.collect();
|
||||
fn slash_command_meta(entry: &SlashCommandEntry) -> serde_json::Map<String, serde_json::Value> {
|
||||
let mut meta = serde_json::Map::new();
|
||||
let command_type = match entry.source {
|
||||
SlashCommandSource::Builtin => "Builtin",
|
||||
SlashCommandSource::Recipe => "Recipe",
|
||||
SlashCommandSource::Skill => "Skill",
|
||||
};
|
||||
meta.insert(
|
||||
"commandType".to_string(),
|
||||
serde_json::Value::String(command_type.to_string()),
|
||||
);
|
||||
if let Some(source_path) = &entry.source_path {
|
||||
meta.insert(
|
||||
"sourcePath".to_string(),
|
||||
serde_json::Value::String(source_path.clone()),
|
||||
);
|
||||
}
|
||||
meta
|
||||
}
|
||||
|
||||
AvailableCommandsUpdate::new(commands)
|
||||
fn slash_command_to_available_command(entry: SlashCommandEntry) -> AvailableCommand {
|
||||
let meta = slash_command_meta(&entry);
|
||||
let mut command = AvailableCommand::new(entry.name, entry.description);
|
||||
if let Some(input_hint) = entry.input_hint {
|
||||
command = command.input(AvailableCommandInput::Unstructured(
|
||||
UnstructuredCommandInput::new(input_hint),
|
||||
));
|
||||
}
|
||||
command.meta(meta)
|
||||
}
|
||||
|
||||
pub(super) fn available_commands_for_working_dir(
|
||||
working_dir: &std::path::Path,
|
||||
) -> Vec<AvailableCommand> {
|
||||
available_commands_for_optional_working_dir(Some(working_dir))
|
||||
}
|
||||
|
||||
pub(super) fn available_commands_for_optional_working_dir(
|
||||
working_dir: Option<&std::path::Path>,
|
||||
) -> Vec<AvailableCommand> {
|
||||
crate::slash_commands::slash_command::list_acp_commands(working_dir)
|
||||
.into_iter()
|
||||
.map(slash_command_to_available_command)
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn available_commands_update(working_dir: &std::path::Path) -> AvailableCommandsUpdate {
|
||||
AvailableCommandsUpdate::new(available_commands_for_working_dir(working_dir))
|
||||
}
|
||||
|
||||
pub(super) fn send_session_setup_notifications(
|
||||
@@ -463,6 +497,49 @@ mod tests {
|
||||
build_mode_state(current_mode)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_slash_command_to_available_command_maps_core_fields_to_acp() {
|
||||
let cases = [
|
||||
(SlashCommandSource::Builtin, "Builtin", None),
|
||||
(
|
||||
SlashCommandSource::Recipe,
|
||||
"Recipe",
|
||||
Some("/tmp/release.yaml".to_string()),
|
||||
),
|
||||
(SlashCommandSource::Skill, "Skill", None),
|
||||
];
|
||||
|
||||
for (source, expected_command_type, expected_source_path) in cases {
|
||||
let command = slash_command_to_available_command(SlashCommandEntry {
|
||||
name: "release".to_string(),
|
||||
description: "Run release workflow".to_string(),
|
||||
source,
|
||||
source_path: expected_source_path.clone(),
|
||||
input_hint: Some("[task]".to_string()),
|
||||
});
|
||||
|
||||
assert_eq!(command.name, "release");
|
||||
assert_eq!(command.description, "Run release workflow");
|
||||
|
||||
match command.input.as_ref() {
|
||||
Some(AvailableCommandInput::Unstructured(input)) => {
|
||||
assert_eq!(input.hint, "[task]");
|
||||
}
|
||||
other => panic!("unexpected command input: {other:?}"),
|
||||
}
|
||||
|
||||
let meta = command.meta.as_ref().expect("command _meta");
|
||||
let expected_command_type = serde_json::json!(expected_command_type);
|
||||
assert_eq!(meta.get("commandType"), Some(&expected_command_type));
|
||||
if let Some(source_path) = expected_source_path {
|
||||
let expected_source_path = serde_json::json!(source_path);
|
||||
assert_eq!(meta.get("sourcePath"), Some(&expected_source_path));
|
||||
} else {
|
||||
assert!(meta.get("sourcePath").is_none());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test_case(
|
||||
build_mode_state(GooseMode::Auto).unwrap(),
|
||||
"openai",
|
||||
|
||||
@@ -82,6 +82,7 @@ use uuid::Uuid;
|
||||
|
||||
mod agent_requests;
|
||||
pub use agent_requests::agent_request_schemas;
|
||||
mod agent_mentions;
|
||||
mod config;
|
||||
mod custom_dispatch;
|
||||
mod diagnostics;
|
||||
@@ -98,6 +99,7 @@ mod onboarding;
|
||||
mod providers;
|
||||
mod recipe;
|
||||
mod resources;
|
||||
mod slash_commands;
|
||||
mod sources;
|
||||
mod tool_notifications;
|
||||
mod tools;
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
use super::*;
|
||||
use crate::session::Session;
|
||||
use goose_sdk_types::custom_requests::{AgentMention, SourceEntry, SourceType};
|
||||
use std::collections::HashSet;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn add_session_subrecipes(
|
||||
session: &Session,
|
||||
sources: &mut Vec<SourceEntry>,
|
||||
seen: &mut HashSet<String>,
|
||||
) {
|
||||
let Some(sub_recipes) = session
|
||||
.recipe
|
||||
.as_ref()
|
||||
.and_then(|recipe| recipe.sub_recipes.as_ref())
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
for sub_recipe in sub_recipes {
|
||||
if !seen.insert(sub_recipe.name.clone()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sources.push(SourceEntry {
|
||||
source_type: SourceType::Subrecipe,
|
||||
name: sub_recipe.name.clone(),
|
||||
description: sub_recipe.description.clone().unwrap_or_default(),
|
||||
content: String::new(),
|
||||
path: sub_recipe.path.clone(),
|
||||
global: false,
|
||||
writable: true,
|
||||
supporting_files: Vec::new(),
|
||||
properties: std::collections::HashMap::new(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl GooseAcpAgent {
|
||||
pub(super) async fn on_list_agent_mentions(
|
||||
&self,
|
||||
req: ListAgentMentionsRequest,
|
||||
) -> Result<ListAgentMentionsResponse, agent_client_protocol::Error> {
|
||||
let session = if let Some(session_id) = req
|
||||
.session_id
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.filter(|session_id| !session_id.is_empty())
|
||||
{
|
||||
Some(
|
||||
self.session_manager
|
||||
.get_session(session_id, false)
|
||||
.await
|
||||
.map_err(|_| {
|
||||
agent_client_protocol::Error::resource_not_found(Some(
|
||||
session_id.to_string(),
|
||||
))
|
||||
.data(format!("Session not found: {}", session_id))
|
||||
})?,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let cwd = if let Some(cwd) = req
|
||||
.cwd
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.filter(|path| !path.is_empty())
|
||||
{
|
||||
PathBuf::from(cwd)
|
||||
} else if let Some(session) = &session {
|
||||
session.working_dir.clone()
|
||||
} else {
|
||||
return Err(agent_client_protocol::Error::invalid_params()
|
||||
.data("Either cwd or sessionId is required"));
|
||||
};
|
||||
|
||||
let filesystem_sources =
|
||||
crate::agents::platform_extensions::summon::discover_filesystem_sources(&cwd);
|
||||
let mut sources = Vec::new();
|
||||
let mut seen = HashSet::new();
|
||||
|
||||
if let Some(session) = &session {
|
||||
add_session_subrecipes(session, &mut sources, &mut seen);
|
||||
}
|
||||
|
||||
for source in filesystem_sources {
|
||||
if seen.insert(source.name.clone()) {
|
||||
sources.push(source);
|
||||
}
|
||||
}
|
||||
|
||||
let agents = sources
|
||||
.into_iter()
|
||||
.filter(|source| {
|
||||
matches!(
|
||||
source.source_type,
|
||||
SourceType::Agent | SourceType::Recipe | SourceType::Subrecipe
|
||||
) && (matches!(
|
||||
source.source_type,
|
||||
SourceType::Recipe | SourceType::Subrecipe
|
||||
) || !source.content.is_empty())
|
||||
})
|
||||
.map(|source| {
|
||||
let mention = format!("@{}", source.name);
|
||||
AgentMention {
|
||||
name: source.name,
|
||||
description: source.description,
|
||||
source_type: source.source_type,
|
||||
source_path: (!source.path.is_empty()).then_some(source.path),
|
||||
mention,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(ListAgentMentionsResponse { agents })
|
||||
}
|
||||
}
|
||||
@@ -480,6 +480,22 @@ impl GooseAcpAgent {
|
||||
self.on_list_sources(req).await
|
||||
}
|
||||
|
||||
#[custom_method(ListAgentMentionsRequest)]
|
||||
async fn dispatch_list_agent_mentions(
|
||||
&self,
|
||||
req: ListAgentMentionsRequest,
|
||||
) -> Result<ListAgentMentionsResponse, agent_client_protocol::Error> {
|
||||
self.on_list_agent_mentions(req).await
|
||||
}
|
||||
|
||||
#[custom_method(ListSlashCommandsRequest)]
|
||||
async fn dispatch_list_slash_commands(
|
||||
&self,
|
||||
req: ListSlashCommandsRequest,
|
||||
) -> Result<ListSlashCommandsResponse, agent_client_protocol::Error> {
|
||||
self.on_list_slash_commands(req).await
|
||||
}
|
||||
|
||||
#[custom_method(UpdateSourceRequest)]
|
||||
async fn dispatch_update_source(
|
||||
&self,
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
use super::*;
|
||||
use std::path::PathBuf;
|
||||
|
||||
impl GooseAcpAgent {
|
||||
pub(super) async fn on_list_slash_commands(
|
||||
&self,
|
||||
req: ListSlashCommandsRequest,
|
||||
) -> Result<ListSlashCommandsResponse, agent_client_protocol::Error> {
|
||||
let cwd = if let Some(cwd) = req
|
||||
.cwd
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.filter(|path| !path.is_empty())
|
||||
{
|
||||
Some(PathBuf::from(cwd))
|
||||
} else if let Some(session_id) = req
|
||||
.session_id
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.filter(|session_id| !session_id.is_empty())
|
||||
{
|
||||
Some(
|
||||
self.session_manager
|
||||
.get_session(session_id, false)
|
||||
.await
|
||||
.map_err(|_| {
|
||||
agent_client_protocol::Error::resource_not_found(Some(
|
||||
session_id.to_string(),
|
||||
))
|
||||
.data(format!("Session not found: {}", session_id))
|
||||
})?
|
||||
.working_dir,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(ListSlashCommandsResponse {
|
||||
available_commands:
|
||||
crate::acp::response_builder::available_commands_for_optional_working_dir(
|
||||
cwd.as_deref(),
|
||||
),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -80,6 +80,7 @@ pub(super) fn commands_from_mappings(mappings: Vec<SlashCommandMapping>) -> Vec<
|
||||
name,
|
||||
description: metadata.description,
|
||||
source: SlashCommandSource::Recipe,
|
||||
source_path: Some(mapping.recipe_path),
|
||||
input_hint: metadata.input_hint,
|
||||
})
|
||||
})
|
||||
|
||||
@@ -73,6 +73,7 @@ pub(super) fn commands_from_sources(sources: Vec<SourceEntry>) -> Vec<SlashComma
|
||||
name,
|
||||
description: source.description,
|
||||
source: SlashCommandSource::Skill,
|
||||
source_path: None,
|
||||
input_hint,
|
||||
})
|
||||
})
|
||||
|
||||
@@ -11,6 +11,7 @@ pub fn list_builtin_commands() -> Vec<SlashCommandEntry> {
|
||||
name: command.name.to_string(),
|
||||
description: command.description.to_string(),
|
||||
source: SlashCommandSource::Builtin,
|
||||
source_path: None,
|
||||
input_hint: None,
|
||||
})
|
||||
.collect()
|
||||
@@ -80,6 +81,7 @@ mod tests {
|
||||
name: name.to_string(),
|
||||
description: format!("{name} description"),
|
||||
source,
|
||||
source_path: None,
|
||||
input_hint: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,5 +10,6 @@ pub struct SlashCommandEntry {
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
pub source: SlashCommandSource,
|
||||
pub source_path: Option<String>,
|
||||
pub input_hint: Option<String>,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
import type { AgentMention, AvailableCommand } from '@aaif/goose-sdk';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { agentMentionToDisplayItem, availableCommandToDisplayItem } from '../autocomplete';
|
||||
|
||||
function command(overrides: Partial<AvailableCommand>): AvailableCommand {
|
||||
return {
|
||||
name: 'release',
|
||||
description: 'Run release workflow',
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function agent(overrides: Partial<AgentMention> = {}): AgentMention {
|
||||
return {
|
||||
name: 'reviewer',
|
||||
description: 'Review code changes',
|
||||
sourceType: 'agent',
|
||||
mention: '@reviewer',
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
describe('ACP autocomplete mapping', () => {
|
||||
it('maps builtin commands to display items with descriptions', () => {
|
||||
expect(
|
||||
availableCommandToDisplayItem(
|
||||
command({
|
||||
_meta: { commandType: 'Builtin' },
|
||||
})
|
||||
)
|
||||
).toEqual({
|
||||
name: 'release',
|
||||
extra: 'Run release workflow',
|
||||
itemType: 'Builtin',
|
||||
relativePath: 'release',
|
||||
});
|
||||
});
|
||||
|
||||
it('maps skill commands to display items with descriptions', () => {
|
||||
expect(
|
||||
availableCommandToDisplayItem(
|
||||
command({
|
||||
_meta: { commandType: 'Skill' },
|
||||
})
|
||||
)
|
||||
).toEqual({
|
||||
name: 'release',
|
||||
extra: 'Run release workflow',
|
||||
itemType: 'Skill',
|
||||
relativePath: 'release',
|
||||
});
|
||||
});
|
||||
|
||||
it('maps recipe commands and prefers sourcePath for display text', () => {
|
||||
expect(
|
||||
availableCommandToDisplayItem(
|
||||
command({
|
||||
_meta: {
|
||||
commandType: 'Recipe',
|
||||
sourcePath: '/tmp/release.yaml',
|
||||
},
|
||||
})
|
||||
)
|
||||
).toEqual({
|
||||
name: 'release',
|
||||
extra: '/tmp/release.yaml',
|
||||
itemType: 'Recipe',
|
||||
relativePath: 'release',
|
||||
});
|
||||
});
|
||||
|
||||
it('falls back to recipe descriptions when sourcePath is missing', () => {
|
||||
expect(
|
||||
availableCommandToDisplayItem(
|
||||
command({
|
||||
_meta: { commandType: 'Recipe' },
|
||||
})
|
||||
)
|
||||
).toEqual({
|
||||
name: 'release',
|
||||
extra: 'Run release workflow',
|
||||
itemType: 'Recipe',
|
||||
relativePath: 'release',
|
||||
});
|
||||
});
|
||||
|
||||
it('skips commands without a valid commandType', () => {
|
||||
expect(availableCommandToDisplayItem(command({}))).toBeNull();
|
||||
expect(
|
||||
availableCommandToDisplayItem(
|
||||
command({
|
||||
_meta: { commandType: 'Agent' },
|
||||
})
|
||||
)
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
it('maps agent mentions and uses server-provided mention text', () => {
|
||||
expect(agentMentionToDisplayItem(agent())).toEqual({
|
||||
name: 'reviewer',
|
||||
extra: 'Review code changes',
|
||||
itemType: 'Agent',
|
||||
relativePath: 'reviewer',
|
||||
insertText: '@reviewer ',
|
||||
});
|
||||
});
|
||||
|
||||
it('does not add a second trailing space to agent mention text', () => {
|
||||
expect(agentMentionToDisplayItem(agent({ mention: '@reviewer ' }))).toMatchObject({
|
||||
insertText: '@reviewer ',
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,76 @@
|
||||
import type { AgentMention, AvailableCommand } from '@aaif/goose-sdk';
|
||||
import type { DisplayItem } from '../components/MentionPopover';
|
||||
import { getAcpClient } from './acpConnection';
|
||||
|
||||
type SlashCommandItemType = Extract<DisplayItem['itemType'], 'Builtin' | 'Recipe' | 'Skill'>;
|
||||
type AutocompleteDisplayItem = DisplayItem;
|
||||
|
||||
const SLASH_COMMAND_ITEM_TYPES = new Set<string>(['Builtin', 'Recipe', 'Skill']);
|
||||
|
||||
function isSlashCommandItemType(value: unknown): value is SlashCommandItemType {
|
||||
return typeof value === 'string' && SLASH_COMMAND_ITEM_TYPES.has(value);
|
||||
}
|
||||
|
||||
function stringMetaValue(
|
||||
meta: AvailableCommand['_meta'],
|
||||
key: string
|
||||
): string | undefined {
|
||||
const value = meta?.[key];
|
||||
return typeof value === 'string' && value.trim() ? value : undefined;
|
||||
}
|
||||
|
||||
function cwdParam(cwd: string): { cwd?: string } {
|
||||
const trimmed = cwd.trim();
|
||||
return trimmed ? { cwd: trimmed } : {};
|
||||
}
|
||||
|
||||
export function availableCommandToDisplayItem(
|
||||
command: AvailableCommand
|
||||
): AutocompleteDisplayItem | null {
|
||||
const commandType = stringMetaValue(command._meta, 'commandType');
|
||||
if (!isSlashCommandItemType(commandType)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const sourcePath = stringMetaValue(command._meta, 'sourcePath');
|
||||
const extra = commandType === 'Recipe' ? sourcePath ?? command.description : command.description;
|
||||
|
||||
return {
|
||||
name: command.name,
|
||||
extra,
|
||||
itemType: commandType,
|
||||
relativePath: command.name,
|
||||
};
|
||||
}
|
||||
|
||||
export function agentMentionToDisplayItem(agent: AgentMention): AutocompleteDisplayItem {
|
||||
const mention = agent.mention.trim() || `@${agent.name}`;
|
||||
|
||||
return {
|
||||
name: agent.name,
|
||||
extra: agent.description,
|
||||
itemType: 'Agent',
|
||||
relativePath: agent.name,
|
||||
insertText: mention.endsWith(' ') ? mention : `${mention} `,
|
||||
};
|
||||
}
|
||||
|
||||
export async function listSlashCommandItems(cwd: string): Promise<AutocompleteDisplayItem[]> {
|
||||
const client = await getAcpClient();
|
||||
const response = await client.goose.slashCommandsList_unstable(cwdParam(cwd));
|
||||
return response.availableCommands
|
||||
.map(availableCommandToDisplayItem)
|
||||
.filter((item): item is AutocompleteDisplayItem => item !== null);
|
||||
}
|
||||
|
||||
export async function listAgentMentionItems(
|
||||
cwd: string,
|
||||
sessionId?: string
|
||||
): Promise<AutocompleteDisplayItem[]> {
|
||||
const client = await getAcpClient();
|
||||
const response = await client.goose.agentMentionsList_unstable({
|
||||
...cwdParam(cwd),
|
||||
...(sessionId ? { sessionId } : {}),
|
||||
});
|
||||
return response.agents.map(agentMentionToDisplayItem);
|
||||
}
|
||||
@@ -1900,6 +1900,7 @@ export default function ChatInput({
|
||||
setMentionPopover((prev) => ({ ...prev, selectedIndex: index }))
|
||||
}
|
||||
workingDir={currentWorkingDir}
|
||||
sessionId={sessionId}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,9 +8,9 @@ import {
|
||||
useState,
|
||||
} from 'react';
|
||||
import { ItemIcon } from './ItemIcon';
|
||||
import { CommandType, getSlashCommands } from '../api';
|
||||
import { getInitialWorkingDir } from '../utils/workingDir';
|
||||
import { defineMessages, useIntl } from '../i18n';
|
||||
import { listAgentMentionItems, listSlashCommandItems } from '../acp/autocomplete';
|
||||
|
||||
const i18n = defineMessages({
|
||||
scanningFiles: {
|
||||
@@ -35,7 +35,8 @@ const i18n = defineMessages({
|
||||
},
|
||||
});
|
||||
|
||||
type DisplayItemType = CommandType | 'Directory' | 'File';
|
||||
type CommandItemType = 'Builtin' | 'Recipe' | 'Skill' | 'Agent';
|
||||
type DisplayItemType = CommandItemType | 'Directory' | 'File';
|
||||
|
||||
const typeOrder: Record<DisplayItemType, number> = {
|
||||
Agent: 0,
|
||||
@@ -51,6 +52,7 @@ export interface DisplayItem {
|
||||
extra: string;
|
||||
itemType: DisplayItemType;
|
||||
relativePath: string;
|
||||
insertText?: string;
|
||||
}
|
||||
|
||||
export interface DisplayItemWithMatch extends DisplayItem {
|
||||
@@ -69,6 +71,7 @@ interface MentionPopoverProps {
|
||||
selectedIndex: number;
|
||||
onSelectedIndexChange: (index: number) => void;
|
||||
workingDir?: string;
|
||||
sessionId?: string | null;
|
||||
}
|
||||
|
||||
// Enhanced fuzzy matching algorithm
|
||||
@@ -150,6 +153,7 @@ const MentionPopover = forwardRef<
|
||||
selectedIndex,
|
||||
onSelectedIndexChange,
|
||||
workingDir,
|
||||
sessionId,
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
@@ -452,6 +456,9 @@ const MentionPopover = forwardRef<
|
||||
}, [items, query, currentWorkingDir]);
|
||||
|
||||
const getSelectionText = (item: DisplayItem): string => {
|
||||
if (item.insertText) {
|
||||
return item.insertText;
|
||||
}
|
||||
if (item.itemType === 'Agent') {
|
||||
return '@' + item.name + ' ';
|
||||
}
|
||||
@@ -484,38 +491,16 @@ const MentionPopover = forwardRef<
|
||||
setIsLoading(true);
|
||||
try {
|
||||
if (isSlashCommand) {
|
||||
const response = await getSlashCommands({
|
||||
query: { working_dir: currentWorkingDir },
|
||||
throwOnError: true,
|
||||
});
|
||||
const commandItems = await listSlashCommandItems(currentWorkingDir);
|
||||
if (cancelled) return;
|
||||
const commandItems: DisplayItem[] = (response.data?.commands || [])
|
||||
.filter((cmd) => cmd.command_type !== 'Agent')
|
||||
.map((cmd) => ({
|
||||
name: cmd.command,
|
||||
extra: cmd.help,
|
||||
itemType: cmd.command_type,
|
||||
relativePath: cmd.command,
|
||||
}));
|
||||
setItems(commandItems);
|
||||
} else {
|
||||
// Fetch agents from server and scan files in parallel
|
||||
const [agentResponse, scannedFiles] = await Promise.all([
|
||||
getSlashCommands({
|
||||
query: { working_dir: currentWorkingDir },
|
||||
throwOnError: true,
|
||||
}).catch(() => null),
|
||||
const [agentItems, scannedFiles] = await Promise.all([
|
||||
listAgentMentionItems(currentWorkingDir, sessionId ?? undefined).catch(() => []),
|
||||
scanDirectoryFromRoot(currentWorkingDir || getDefaultStartPath()),
|
||||
]);
|
||||
if (cancelled) return;
|
||||
const agentItems: DisplayItem[] = (agentResponse?.data?.commands || [])
|
||||
.filter((cmd) => cmd.command_type === 'Agent')
|
||||
.map((cmd) => ({
|
||||
name: cmd.command,
|
||||
extra: cmd.help,
|
||||
itemType: cmd.command_type,
|
||||
relativePath: cmd.command,
|
||||
}));
|
||||
setItems([...agentItems, ...scannedFiles]);
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -537,7 +522,7 @@ const MentionPopover = forwardRef<
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [isOpen, isSlashCommand, scanDirectoryFromRoot, currentWorkingDir]);
|
||||
}, [isOpen, isSlashCommand, scanDirectoryFromRoot, currentWorkingDir, sessionId]);
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
@@ -610,7 +595,7 @@ const MentionPopover = forwardRef<
|
||||
>
|
||||
{displayItems.map((item, index) => (
|
||||
<div
|
||||
key={`${item.itemType}-${item.name}`}
|
||||
key={`${item.itemType}-${item.relativePath}-${item.extra}-${item.insertText ?? ''}`}
|
||||
onClick={() => handleItemClick(index)}
|
||||
data-selected={index === selectedIndex}
|
||||
className={`flex items-center gap-3 p-2 rounded-md cursor-pointer transition-colors ${
|
||||
|
||||
@@ -69,10 +69,14 @@ import type {
|
||||
ImportSessionResponse_unstable,
|
||||
ImportSourcesRequest_unstable,
|
||||
ImportSourcesResponse_unstable,
|
||||
ListAgentMentionsRequest_unstable,
|
||||
ListAgentMentionsResponse_unstable,
|
||||
ListProvidersRequest_unstable,
|
||||
ListProvidersResponse_unstable,
|
||||
ListRecipesRequest_unstable,
|
||||
ListRecipesResponse_unstable,
|
||||
ListSlashCommandsRequest_unstable,
|
||||
ListSlashCommandsResponse_unstable,
|
||||
ListSourcesRequest_unstable,
|
||||
ListSourcesResponse_unstable,
|
||||
OnboardingImportApplyRequest_unstable,
|
||||
@@ -154,8 +158,10 @@ import {
|
||||
zGooseToolCallResponse_unstable,
|
||||
zImportSessionResponse_unstable,
|
||||
zImportSourcesResponse_unstable,
|
||||
zListAgentMentionsResponse_unstable,
|
||||
zListProvidersResponse_unstable,
|
||||
zListRecipesResponse_unstable,
|
||||
zListSlashCommandsResponse_unstable,
|
||||
zListSourcesResponse_unstable,
|
||||
zOnboardingImportApplyResponse_unstable,
|
||||
zOnboardingImportScanResponse_unstable,
|
||||
@@ -777,6 +783,30 @@ export class GooseExtClient {
|
||||
) as ListSourcesResponse_unstable;
|
||||
}
|
||||
|
||||
async agentMentionsList_unstable(
|
||||
params: ListAgentMentionsRequest_unstable,
|
||||
): Promise<ListAgentMentionsResponse_unstable> {
|
||||
const raw = await this.conn.extMethod(
|
||||
"_goose/unstable/agent-mentions/list",
|
||||
params,
|
||||
);
|
||||
return zListAgentMentionsResponse_unstable.parse(
|
||||
raw,
|
||||
) as ListAgentMentionsResponse_unstable;
|
||||
}
|
||||
|
||||
async slashCommandsList_unstable(
|
||||
params: ListSlashCommandsRequest_unstable,
|
||||
): Promise<ListSlashCommandsResponse_unstable> {
|
||||
const raw = await this.conn.extMethod(
|
||||
"_goose/unstable/slash-commands/list",
|
||||
params,
|
||||
);
|
||||
return zListSlashCommandsResponse_unstable.parse(
|
||||
raw,
|
||||
) as ListSlashCommandsResponse_unstable;
|
||||
}
|
||||
|
||||
async sourcesUpdate_unstable(
|
||||
params: UpdateSourceRequest_unstable,
|
||||
): Promise<UpdateSourceResponse_unstable> {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1538,6 +1538,94 @@ export type ListSourcesResponse_unstable = {
|
||||
sources: Array<SourceEntry>;
|
||||
};
|
||||
|
||||
/**
|
||||
* List user-facing agent mention targets for `@` autocomplete.
|
||||
*/
|
||||
export type ListAgentMentionsRequest_unstable = {
|
||||
cwd?: string | null;
|
||||
sessionId?: string | null;
|
||||
};
|
||||
|
||||
export type ListAgentMentionsResponse_unstable = {
|
||||
agents: Array<AgentMention>;
|
||||
};
|
||||
|
||||
/**
|
||||
* A user-facing `@` mention target backed by an agent, recipe, or subrecipe source.
|
||||
*/
|
||||
export type AgentMention = {
|
||||
name: string;
|
||||
description: string;
|
||||
sourceType: SourceType;
|
||||
sourcePath?: string | null;
|
||||
mention: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* List slash commands available for `/` autocomplete.
|
||||
*/
|
||||
export type ListSlashCommandsRequest_unstable = {
|
||||
cwd?: string | null;
|
||||
sessionId?: string | null;
|
||||
};
|
||||
|
||||
export type ListSlashCommandsResponse_unstable = {
|
||||
availableCommands: Array<AvailableCommand>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Information about a command.
|
||||
*/
|
||||
export type AvailableCommand = {
|
||||
/**
|
||||
* Command name (e.g., `create_plan`, `research_codebase`).
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* Human-readable description of what the command does.
|
||||
*/
|
||||
description: string;
|
||||
/**
|
||||
* Input for the command if required
|
||||
*/
|
||||
input?: AvailableCommandInput | null;
|
||||
/**
|
||||
* The _meta property is reserved by ACP to allow clients and agents to attach additional
|
||||
* metadata to their interactions. Implementations MUST NOT make assumptions about values at
|
||||
* these keys.
|
||||
*
|
||||
* See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
|
||||
*/
|
||||
_meta?: {
|
||||
[key: string]: unknown;
|
||||
} | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* All text that was typed after the command name is provided as input.
|
||||
*/
|
||||
export type AvailableCommandInput = UnstructuredCommandInput;
|
||||
|
||||
/**
|
||||
* All text that was typed after the command name is provided as input.
|
||||
*/
|
||||
export type UnstructuredCommandInput = {
|
||||
/**
|
||||
* A hint to display when the input hasn't been provided yet
|
||||
*/
|
||||
hint: string;
|
||||
/**
|
||||
* The _meta property is reserved by ACP to allow clients and agents to attach additional
|
||||
* metadata to their interactions. Implementations MUST NOT make assumptions about values at
|
||||
* these keys.
|
||||
*
|
||||
* See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
|
||||
*/
|
||||
_meta?: {
|
||||
[key: string]: unknown;
|
||||
} | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Update an existing source's name, description, and content by absolute path.
|
||||
*/
|
||||
@@ -1817,14 +1905,14 @@ export type RecipeParamsAction = 'submit' | 'cancel';
|
||||
export type ExtRequest = {
|
||||
id: string;
|
||||
method: string;
|
||||
params?: AddSessionExtensionRequest_unstable | RemoveSessionExtensionRequest_unstable | GetToolsRequest_unstable | GooseToolCallRequest_unstable | ReadResourceRequest_unstable | UpdateWorkingDirRequest_unstable | SetSessionSystemPromptRequest_unstable | SteerSessionRequest_unstable | DiagnosticsGetRequest_unstable | DeleteSessionRequest | GetConfigExtensionsRequest_unstable | GetAvailableExtensionsRequest_unstable | AddConfigExtensionRequest_unstable | RemoveConfigExtensionRequest_unstable | SetConfigExtensionEnabledRequest_unstable | GetSessionExtensionsRequest_unstable | ListProvidersRequest_unstable | ProviderSupportedModelsListRequest_unstable | ProviderCatalogListRequest_unstable | ProviderSetupCatalogListRequest_unstable | ProviderCatalogTemplateRequest_unstable | CustomProviderCreateRequest_unstable | CustomProviderReadRequest_unstable | CustomProviderUpdateRequest_unstable | CustomProviderDeleteRequest_unstable | RefreshProviderInventoryRequest_unstable | ProviderConfigReadRequest_unstable | ProviderConfigStatusRequest_unstable | ProviderConfigSaveRequest_unstable | ProviderConfigDeleteRequest_unstable | ProviderConfigAuthenticateRequest_unstable | PreferencesReadRequest_unstable | PreferencesSaveRequest_unstable | PreferencesRemoveRequest_unstable | DefaultsReadRequest_unstable | DefaultsSaveRequest_unstable | OnboardingImportScanRequest_unstable | OnboardingImportApplyRequest_unstable | ExportSessionRequest_unstable | ImportSessionRequest_unstable | EncodeRecipeRequest_unstable | DecodeRecipeRequest_unstable | ScanRecipeRequest_unstable | ListRecipesRequest_unstable | DeleteRecipeRequest_unstable | ScheduleRecipeRequest_unstable | SetRecipeSlashCommandRequest_unstable | SaveRecipeRequest_unstable | ParseRecipeRequest_unstable | RecipeToYamlRequest_unstable | GetSessionInfoRequest_unstable | TruncateSessionConversationRequest_unstable | UpdateSessionProjectRequest_unstable | RenameSessionRequest_unstable | ArchiveSessionRequest_unstable | UnarchiveSessionRequest_unstable | CreateSourceRequest_unstable | ListSourcesRequest_unstable | UpdateSourceRequest_unstable | DeleteSourceRequest_unstable | ExportSourceRequest_unstable | ImportSourcesRequest_unstable | DictationTranscribeRequest_unstable | DictationConfigRequest_unstable | DictationSecretSaveRequest_unstable | DictationSecretDeleteRequest_unstable | DictationModelsListRequest_unstable | DictationModelDownloadRequest_unstable | DictationModelDownloadProgressRequest_unstable | DictationModelCancelRequest_unstable | DictationModelDeleteRequest_unstable | DictationModelSelectRequest_unstable | {
|
||||
params?: AddSessionExtensionRequest_unstable | RemoveSessionExtensionRequest_unstable | GetToolsRequest_unstable | GooseToolCallRequest_unstable | ReadResourceRequest_unstable | UpdateWorkingDirRequest_unstable | SetSessionSystemPromptRequest_unstable | SteerSessionRequest_unstable | DiagnosticsGetRequest_unstable | DeleteSessionRequest | GetConfigExtensionsRequest_unstable | GetAvailableExtensionsRequest_unstable | AddConfigExtensionRequest_unstable | RemoveConfigExtensionRequest_unstable | SetConfigExtensionEnabledRequest_unstable | GetSessionExtensionsRequest_unstable | ListProvidersRequest_unstable | ProviderSupportedModelsListRequest_unstable | ProviderCatalogListRequest_unstable | ProviderSetupCatalogListRequest_unstable | ProviderCatalogTemplateRequest_unstable | CustomProviderCreateRequest_unstable | CustomProviderReadRequest_unstable | CustomProviderUpdateRequest_unstable | CustomProviderDeleteRequest_unstable | RefreshProviderInventoryRequest_unstable | ProviderConfigReadRequest_unstable | ProviderConfigStatusRequest_unstable | ProviderConfigSaveRequest_unstable | ProviderConfigDeleteRequest_unstable | ProviderConfigAuthenticateRequest_unstable | PreferencesReadRequest_unstable | PreferencesSaveRequest_unstable | PreferencesRemoveRequest_unstable | DefaultsReadRequest_unstable | DefaultsSaveRequest_unstable | OnboardingImportScanRequest_unstable | OnboardingImportApplyRequest_unstable | ExportSessionRequest_unstable | ImportSessionRequest_unstable | EncodeRecipeRequest_unstable | DecodeRecipeRequest_unstable | ScanRecipeRequest_unstable | ListRecipesRequest_unstable | DeleteRecipeRequest_unstable | ScheduleRecipeRequest_unstable | SetRecipeSlashCommandRequest_unstable | SaveRecipeRequest_unstable | ParseRecipeRequest_unstable | RecipeToYamlRequest_unstable | GetSessionInfoRequest_unstable | TruncateSessionConversationRequest_unstable | UpdateSessionProjectRequest_unstable | RenameSessionRequest_unstable | ArchiveSessionRequest_unstable | UnarchiveSessionRequest_unstable | CreateSourceRequest_unstable | ListSourcesRequest_unstable | ListAgentMentionsRequest_unstable | ListSlashCommandsRequest_unstable | UpdateSourceRequest_unstable | DeleteSourceRequest_unstable | ExportSourceRequest_unstable | ImportSourcesRequest_unstable | DictationTranscribeRequest_unstable | DictationConfigRequest_unstable | DictationSecretSaveRequest_unstable | DictationSecretDeleteRequest_unstable | DictationModelsListRequest_unstable | DictationModelDownloadRequest_unstable | DictationModelDownloadProgressRequest_unstable | DictationModelCancelRequest_unstable | DictationModelDeleteRequest_unstable | DictationModelSelectRequest_unstable | {
|
||||
[key: string]: unknown;
|
||||
} | null;
|
||||
};
|
||||
|
||||
export type ExtResponse = {
|
||||
id: string;
|
||||
result?: EmptyResponse | GetToolsResponse_unstable | GooseToolCallResponse_unstable | ReadResourceResponse_unstable | SteerSessionResponse_unstable | DiagnosticsGetResponse_unstable | GetConfigExtensionsResponse_unstable | GetAvailableExtensionsResponse_unstable | GetSessionExtensionsResponse_unstable | ListProvidersResponse_unstable | ProviderSupportedModelsListResponse_unstable | ProviderCatalogListResponse_unstable | ProviderSetupCatalogListResponse_unstable | ProviderCatalogTemplateResponse_unstable | CustomProviderCreateResponse_unstable | CustomProviderReadResponse_unstable | CustomProviderUpdateResponse_unstable | CustomProviderDeleteResponse_unstable | RefreshProviderInventoryResponse_unstable | ProviderConfigReadResponse_unstable | ProviderConfigStatusResponse_unstable | ProviderConfigChangeResponse_unstable | PreferencesReadResponse_unstable | DefaultsReadResponse_unstable | OnboardingImportScanResponse_unstable | OnboardingImportApplyResponse_unstable | ExportSessionResponse_unstable | ImportSessionResponse_unstable | EncodeRecipeResponse_unstable | DecodeRecipeResponse_unstable | ScanRecipeResponse_unstable | ListRecipesResponse_unstable | SaveRecipeResponse_unstable | ParseRecipeResponse_unstable | RecipeToYamlResponse_unstable | GetSessionInfoResponse_unstable | CreateSourceResponse_unstable | ListSourcesResponse_unstable | UpdateSourceResponse_unstable | ExportSourceResponse_unstable | ImportSourcesResponse_unstable | DictationTranscribeResponse_unstable | DictationConfigResponse_unstable | DictationModelsListResponse_unstable | DictationModelDownloadProgressResponse_unstable | unknown;
|
||||
result?: EmptyResponse | GetToolsResponse_unstable | GooseToolCallResponse_unstable | ReadResourceResponse_unstable | SteerSessionResponse_unstable | DiagnosticsGetResponse_unstable | GetConfigExtensionsResponse_unstable | GetAvailableExtensionsResponse_unstable | GetSessionExtensionsResponse_unstable | ListProvidersResponse_unstable | ProviderSupportedModelsListResponse_unstable | ProviderCatalogListResponse_unstable | ProviderSetupCatalogListResponse_unstable | ProviderCatalogTemplateResponse_unstable | CustomProviderCreateResponse_unstable | CustomProviderReadResponse_unstable | CustomProviderUpdateResponse_unstable | CustomProviderDeleteResponse_unstable | RefreshProviderInventoryResponse_unstable | ProviderConfigReadResponse_unstable | ProviderConfigStatusResponse_unstable | ProviderConfigChangeResponse_unstable | PreferencesReadResponse_unstable | DefaultsReadResponse_unstable | OnboardingImportScanResponse_unstable | OnboardingImportApplyResponse_unstable | ExportSessionResponse_unstable | ImportSessionResponse_unstable | EncodeRecipeResponse_unstable | DecodeRecipeResponse_unstable | ScanRecipeResponse_unstable | ListRecipesResponse_unstable | SaveRecipeResponse_unstable | ParseRecipeResponse_unstable | RecipeToYamlResponse_unstable | GetSessionInfoResponse_unstable | CreateSourceResponse_unstable | ListSourcesResponse_unstable | ListAgentMentionsResponse_unstable | ListSlashCommandsResponse_unstable | UpdateSourceResponse_unstable | ExportSourceResponse_unstable | ImportSourcesResponse_unstable | DictationTranscribeResponse_unstable | DictationConfigResponse_unstable | DictationModelsListResponse_unstable | DictationModelDownloadProgressResponse_unstable | unknown;
|
||||
} | {
|
||||
error: {
|
||||
code: number;
|
||||
|
||||
@@ -1639,6 +1639,88 @@ export const zListSourcesResponse_unstable = z.object({
|
||||
sources: z.array(zSourceEntry)
|
||||
});
|
||||
|
||||
/**
|
||||
* List user-facing agent mention targets for `@` autocomplete.
|
||||
*/
|
||||
export const zListAgentMentionsRequest_unstable = z.object({
|
||||
cwd: z.union([
|
||||
z.string(),
|
||||
z.null()
|
||||
]).optional(),
|
||||
sessionId: z.union([
|
||||
z.string(),
|
||||
z.null()
|
||||
]).optional()
|
||||
});
|
||||
|
||||
/**
|
||||
* A user-facing `@` mention target backed by an agent, recipe, or subrecipe source.
|
||||
*/
|
||||
export const zAgentMention = z.object({
|
||||
name: z.string(),
|
||||
description: z.string(),
|
||||
sourceType: zSourceType,
|
||||
sourcePath: z.union([
|
||||
z.string(),
|
||||
z.null()
|
||||
]).optional(),
|
||||
mention: z.string()
|
||||
});
|
||||
|
||||
export const zListAgentMentionsResponse_unstable = z.object({
|
||||
agents: z.array(zAgentMention)
|
||||
});
|
||||
|
||||
/**
|
||||
* List slash commands available for `/` autocomplete.
|
||||
*/
|
||||
export const zListSlashCommandsRequest_unstable = z.object({
|
||||
cwd: z.union([
|
||||
z.string(),
|
||||
z.null()
|
||||
]).optional(),
|
||||
sessionId: z.union([
|
||||
z.string(),
|
||||
z.null()
|
||||
]).optional()
|
||||
});
|
||||
|
||||
/**
|
||||
* All text that was typed after the command name is provided as input.
|
||||
*/
|
||||
export const zUnstructuredCommandInput = z.object({
|
||||
hint: z.string(),
|
||||
_meta: z.union([
|
||||
z.record(z.unknown()),
|
||||
z.null()
|
||||
]).optional()
|
||||
});
|
||||
|
||||
/**
|
||||
* All text that was typed after the command name is provided as input.
|
||||
*/
|
||||
export const zAvailableCommandInput = zUnstructuredCommandInput;
|
||||
|
||||
/**
|
||||
* Information about a command.
|
||||
*/
|
||||
export const zAvailableCommand = z.object({
|
||||
name: z.string(),
|
||||
description: z.string(),
|
||||
input: z.union([
|
||||
zAvailableCommandInput,
|
||||
z.null()
|
||||
]).optional(),
|
||||
_meta: z.union([
|
||||
z.record(z.unknown()),
|
||||
z.null()
|
||||
]).optional()
|
||||
});
|
||||
|
||||
export const zListSlashCommandsResponse_unstable = z.object({
|
||||
availableCommands: z.array(zAvailableCommand)
|
||||
});
|
||||
|
||||
/**
|
||||
* Update an existing source's name, description, and content by absolute path.
|
||||
*/
|
||||
@@ -1982,6 +2064,8 @@ export const zExtRequest = z.object({
|
||||
zUnarchiveSessionRequest_unstable,
|
||||
zCreateSourceRequest_unstable,
|
||||
zListSourcesRequest_unstable,
|
||||
zListAgentMentionsRequest_unstable,
|
||||
zListSlashCommandsRequest_unstable,
|
||||
zUpdateSourceRequest_unstable,
|
||||
zDeleteSourceRequest_unstable,
|
||||
zExportSourceRequest_unstable,
|
||||
@@ -2047,6 +2131,8 @@ export const zExtResponse = z.union([
|
||||
zGetSessionInfoResponse_unstable,
|
||||
zCreateSourceResponse_unstable,
|
||||
zListSourcesResponse_unstable,
|
||||
zListAgentMentionsResponse_unstable,
|
||||
zListSlashCommandsResponse_unstable,
|
||||
zUpdateSourceResponse_unstable,
|
||||
zExportSourceResponse_unstable,
|
||||
zImportSourcesResponse_unstable,
|
||||
|
||||
Reference in New Issue
Block a user