mirror of
https://github.com/block/goose.git
synced 2026-07-09 16:09:22 +00:00
feat(acp): migrate upsertPermissions to setToolPermissions ACP method (#9999)
This commit is contained in:
parent
59b28e455f
commit
22883e3704
17 changed files with 387 additions and 196 deletions
|
|
@ -51,13 +51,28 @@ pub struct RemoveSessionExtensionRequest {
|
|||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GetToolsRequest {
|
||||
pub session_id: String,
|
||||
/// Filter tools to those belonging to this extension.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub extension_name: Option<String>,
|
||||
}
|
||||
|
||||
/// A single tool item returned by the tools list endpoint.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ToolListItem {
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
pub parameters: Vec<String>,
|
||||
pub permission: Option<ToolPermissionLevel>,
|
||||
pub input_schema: serde_json::Value,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub output_schema: Option<serde_json::Value>,
|
||||
}
|
||||
|
||||
/// Tools response.
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema, JsonRpcResponse)]
|
||||
pub struct GetToolsResponse {
|
||||
/// Array of tool info objects with `name`, `description`, `parameters`, and optional `permission`.
|
||||
pub tools: Vec<serde_json::Value>,
|
||||
pub tools: Vec<ToolListItem>,
|
||||
}
|
||||
|
||||
/// Read a resource from an extension.
|
||||
|
|
@ -1620,3 +1635,32 @@ pub struct DictationModelSelectRequest {
|
|||
pub provider: String,
|
||||
pub model_id: String,
|
||||
}
|
||||
|
||||
/// Permission level for a tool.
|
||||
#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ToolPermissionLevel {
|
||||
AlwaysAllow,
|
||||
#[default]
|
||||
AskBefore,
|
||||
NeverAllow,
|
||||
}
|
||||
|
||||
/// A single tool permission entry.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ToolPermissionEntry {
|
||||
pub tool_name: String,
|
||||
pub permission: ToolPermissionLevel,
|
||||
}
|
||||
|
||||
/// Set permission levels for one or more tools.
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema, JsonRpcRequest)]
|
||||
#[request(method = "_goose/unstable/tools/permissions/set", response = SetToolPermissionsResponse)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SetToolPermissionsRequest {
|
||||
pub tool_permissions: Vec<ToolPermissionEntry>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema, JsonRpcResponse)]
|
||||
pub struct SetToolPermissionsResponse {}
|
||||
|
|
|
|||
|
|
@ -409,7 +409,6 @@ derive_utoipa!(IconTheme as IconThemeSchema);
|
|||
super::routes::config_management::get_provider_models,
|
||||
super::routes::config_management::get_provider_model_info,
|
||||
super::routes::config_management::get_slash_commands,
|
||||
super::routes::config_management::upsert_permissions,
|
||||
super::routes::config_management::create_custom_provider,
|
||||
super::routes::config_management::get_custom_provider,
|
||||
super::routes::config_management::update_custom_provider,
|
||||
|
|
@ -489,8 +488,6 @@ derive_utoipa!(IconTheme as IconThemeSchema);
|
|||
super::routes::config_management::CommandType,
|
||||
super::routes::config_management::ExtensionResponse,
|
||||
super::routes::config_management::ExtensionQuery,
|
||||
super::routes::config_management::ToolPermission,
|
||||
super::routes::config_management::UpsertPermissionsQuery,
|
||||
super::routes::config_management::UpdateCustomProviderRequest,
|
||||
goose::providers::catalog::ProviderCatalogEntry,
|
||||
goose::providers::catalog::ProviderTemplate,
|
||||
|
|
|
|||
|
|
@ -23,8 +23,7 @@ use goose::providers::create_with_default_model;
|
|||
use goose::providers::huggingface_auth;
|
||||
use goose::providers::providers as get_providers;
|
||||
use goose::{
|
||||
agents::execute_commands, agents::ExtensionConfig, config::permission::PermissionLevel,
|
||||
slash_commands::recipe_slash_command,
|
||||
agents::execute_commands, agents::ExtensionConfig, slash_commands::recipe_slash_command,
|
||||
};
|
||||
use goose_providers::model::ModelConfig;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
|
@ -83,17 +82,6 @@ pub struct ProvidersResponse {
|
|||
pub providers: Vec<ProviderDetails>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct ToolPermission {
|
||||
pub tool_name: String,
|
||||
pub permission: PermissionLevel,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, ToSchema)]
|
||||
pub struct UpsertPermissionsQuery {
|
||||
pub tool_permissions: Vec<ToolPermission>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, ToSchema)]
|
||||
pub struct UpdateCustomProviderRequest {
|
||||
pub engine: String,
|
||||
|
|
@ -1139,30 +1127,6 @@ pub async fn get_canonical_model_info(
|
|||
})
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
post,
|
||||
path = "/config/permissions",
|
||||
request_body = UpsertPermissionsQuery,
|
||||
responses(
|
||||
(status = 200, description = "Permission update completed", body = String),
|
||||
(status = 400, description = "Invalid request"),
|
||||
)
|
||||
)]
|
||||
pub async fn upsert_permissions(
|
||||
Json(query): Json<UpsertPermissionsQuery>,
|
||||
) -> Result<Json<String>, ErrorResponse> {
|
||||
let permission_manager = goose::config::PermissionManager::instance();
|
||||
|
||||
for tool_permission in &query.tool_permissions {
|
||||
permission_manager.update_user_permission(
|
||||
&tool_permission.tool_name,
|
||||
tool_permission.permission.clone(),
|
||||
);
|
||||
}
|
||||
|
||||
Ok(Json("Permissions updated successfully".to_string()))
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/config/validate",
|
||||
|
|
@ -1495,7 +1459,6 @@ pub fn routes(state: Arc<AppState>) -> Router {
|
|||
post(get_canonical_model_info),
|
||||
)
|
||||
.route("/config/validate", get(validate_config))
|
||||
.route("/config/permissions", post(upsert_permissions))
|
||||
.route("/config/custom-providers", post(create_custom_provider))
|
||||
.route(
|
||||
"/config/custom-providers/{id}",
|
||||
|
|
|
|||
|
|
@ -15,6 +15,11 @@
|
|||
"requestType": "GetToolsRequest_unstable",
|
||||
"responseType": "GetToolsResponse_unstable"
|
||||
},
|
||||
{
|
||||
"method": "_goose/unstable/tools/permissions/set",
|
||||
"requestType": "SetToolPermissionsRequest_unstable",
|
||||
"responseType": "SetToolPermissionsResponse_unstable"
|
||||
},
|
||||
{
|
||||
"method": "_goose/unstable/tools/call",
|
||||
"requestType": "GooseToolCallRequest_unstable",
|
||||
|
|
|
|||
|
|
@ -383,6 +383,13 @@
|
|||
"properties": {
|
||||
"sessionId": {
|
||||
"type": "string"
|
||||
},
|
||||
"extensionName": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"description": "Filter tools to those belonging to this extension."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
|
|
@ -397,8 +404,9 @@
|
|||
"properties": {
|
||||
"tools": {
|
||||
"type": "array",
|
||||
"items": {},
|
||||
"description": "Array of tool info objects with `name`, `description`, `parameters`, and optional `permission`."
|
||||
"items": {
|
||||
"$ref": "#/$defs/ToolListItem"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
|
|
@ -408,6 +416,89 @@
|
|||
"x-side": "agent",
|
||||
"x-method": "_goose/unstable/tools/list"
|
||||
},
|
||||
"ToolListItem": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"parameters": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"permission": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/$defs/ToolPermissionLevel"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"inputSchema": {},
|
||||
"outputSchema": {}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"description",
|
||||
"parameters",
|
||||
"inputSchema"
|
||||
],
|
||||
"description": "A single tool item returned by the tools list endpoint."
|
||||
},
|
||||
"ToolPermissionLevel": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"always_allow",
|
||||
"ask_before",
|
||||
"never_allow"
|
||||
],
|
||||
"description": "Permission level for a tool."
|
||||
},
|
||||
"SetToolPermissionsRequest_unstable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"toolPermissions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/ToolPermissionEntry"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"toolPermissions"
|
||||
],
|
||||
"description": "Set permission levels for one or more tools.",
|
||||
"x-side": "agent",
|
||||
"x-method": "_goose/unstable/tools/permissions/set"
|
||||
},
|
||||
"ToolPermissionEntry": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"toolName": {
|
||||
"type": "string"
|
||||
},
|
||||
"permission": {
|
||||
"$ref": "#/$defs/ToolPermissionLevel"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"toolName",
|
||||
"permission"
|
||||
],
|
||||
"description": "A single tool permission entry."
|
||||
},
|
||||
"SetToolPermissionsResponse_unstable": {
|
||||
"type": "object",
|
||||
"x-side": "agent",
|
||||
"x-method": "_goose/unstable/tools/permissions/set"
|
||||
},
|
||||
"GooseToolCallRequest_unstable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
@ -5225,6 +5316,15 @@
|
|||
"description": "Params for _goose/unstable/tools/list",
|
||||
"title": "GetToolsRequest_unstable"
|
||||
},
|
||||
{
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/$defs/SetToolPermissionsRequest_unstable"
|
||||
}
|
||||
],
|
||||
"description": "Params for _goose/unstable/tools/permissions/set",
|
||||
"title": "SetToolPermissionsRequest_unstable"
|
||||
},
|
||||
{
|
||||
"allOf": [
|
||||
{
|
||||
|
|
@ -6036,6 +6136,14 @@
|
|||
],
|
||||
"title": "GetToolsResponse_unstable"
|
||||
},
|
||||
{
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/$defs/SetToolPermissionsResponse_unstable"
|
||||
}
|
||||
],
|
||||
"title": "SetToolPermissionsResponse_unstable"
|
||||
},
|
||||
{
|
||||
"allOf": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -42,6 +42,14 @@ impl GooseAcpAgent {
|
|||
self.on_get_tools(req).await
|
||||
}
|
||||
|
||||
#[custom_method(SetToolPermissionsRequest)]
|
||||
async fn dispatch_set_tool_permissions(
|
||||
&self,
|
||||
req: SetToolPermissionsRequest,
|
||||
) -> Result<SetToolPermissionsResponse, agent_client_protocol::Error> {
|
||||
self.on_set_tool_permissions(req).await
|
||||
}
|
||||
|
||||
#[custom_method(GooseToolCallRequest)]
|
||||
async fn dispatch_call_tool(
|
||||
&self,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
use super::*;
|
||||
use crate::agents::extension_manager::get_parameter_names;
|
||||
use crate::agents::reply_parts::is_tool_visible_to_app;
|
||||
use crate::config::permission::PermissionLevel;
|
||||
use goose_sdk_types::custom_requests::{ToolListItem, ToolPermissionLevel};
|
||||
use rmcp::model::CallToolRequestParams;
|
||||
|
||||
impl GooseAcpAgent {
|
||||
|
|
@ -9,13 +12,51 @@ impl GooseAcpAgent {
|
|||
) -> Result<GetToolsResponse, agent_client_protocol::Error> {
|
||||
let session_id = &req.session_id;
|
||||
let agent = self.get_session_agent(&req.session_id).await?;
|
||||
let tools = agent.list_tools(session_id, None).await;
|
||||
let tools_json = tools
|
||||
let goose_mode = agent.goose_mode().await;
|
||||
// Read from the global static manager so REST-based confirmToolAction approvals
|
||||
// (which update PermissionManager::instance()) are reflected here immediately.
|
||||
let permission_manager = crate::config::PermissionManager::instance();
|
||||
|
||||
let mut tools: Vec<ToolListItem> = agent
|
||||
.list_tools(session_id, req.extension_name)
|
||||
.await
|
||||
.into_iter()
|
||||
.map(|t| serde_json::to_value(&t))
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.internal_err()?;
|
||||
Ok(GetToolsResponse { tools: tools_json })
|
||||
.map(|tool| {
|
||||
let permission = permission_manager
|
||||
.get_user_permission(&tool.name)
|
||||
.or_else(|| {
|
||||
if goose_mode == GooseMode::SmartApprove {
|
||||
permission_manager.get_smart_approve_permission(&tool.name)
|
||||
} else if goose_mode == GooseMode::Approve {
|
||||
Some(PermissionLevel::AskBefore)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.map(|p| match p {
|
||||
PermissionLevel::AlwaysAllow => ToolPermissionLevel::AlwaysAllow,
|
||||
PermissionLevel::AskBefore => ToolPermissionLevel::AskBefore,
|
||||
PermissionLevel::NeverAllow => ToolPermissionLevel::NeverAllow,
|
||||
});
|
||||
ToolListItem {
|
||||
name: tool.name.to_string(),
|
||||
description: tool
|
||||
.description
|
||||
.as_ref()
|
||||
.map(|d| d.as_ref().to_string())
|
||||
.unwrap_or_default(),
|
||||
parameters: get_parameter_names(&tool),
|
||||
permission,
|
||||
input_schema: serde_json::Value::Object(tool.input_schema.as_ref().clone()),
|
||||
output_schema: tool
|
||||
.output_schema
|
||||
.as_ref()
|
||||
.map(|s| serde_json::to_value(s).unwrap_or(serde_json::Value::Null)),
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
tools.sort_by(|a, b| a.name.cmp(&b.name));
|
||||
Ok(GetToolsResponse { tools })
|
||||
}
|
||||
|
||||
pub(super) async fn on_call_tool(
|
||||
|
|
@ -78,4 +119,23 @@ impl GooseAcpAgent {
|
|||
meta: result.meta.and_then(|m| serde_json::to_value(m).ok()),
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) async fn on_set_tool_permissions(
|
||||
&self,
|
||||
req: SetToolPermissionsRequest,
|
||||
) -> Result<SetToolPermissionsResponse, agent_client_protocol::Error> {
|
||||
let acp_permission_manager = self.permission_manager();
|
||||
// Also update the global static manager used by HTTP agents when USE_ACP_CHAT is false.
|
||||
let global_permission_manager = crate::config::PermissionManager::instance();
|
||||
for entry in &req.tool_permissions {
|
||||
let level = match entry.permission {
|
||||
ToolPermissionLevel::AlwaysAllow => PermissionLevel::AlwaysAllow,
|
||||
ToolPermissionLevel::AskBefore => PermissionLevel::AskBefore,
|
||||
ToolPermissionLevel::NeverAllow => PermissionLevel::NeverAllow,
|
||||
};
|
||||
acp_permission_manager.update_user_permission(&entry.tool_name, level.clone());
|
||||
global_permission_manager.update_user_permission(&entry.tool_name, level);
|
||||
}
|
||||
Ok(SetToolPermissionsResponse {})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -791,39 +791,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/config/permissions": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"super::routes::config_management"
|
||||
],
|
||||
"operationId": "upsert_permissions",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UpsertPermissionsQuery"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Permission update completed",
|
||||
"content": {
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid request"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/config/prompts": {
|
||||
"get": {
|
||||
"tags": [
|
||||
|
|
@ -8363,21 +8330,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"ToolPermission": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"tool_name",
|
||||
"permission"
|
||||
],
|
||||
"properties": {
|
||||
"permission": {
|
||||
"$ref": "#/components/schemas/PermissionLevel"
|
||||
},
|
||||
"tool_name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ToolRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
|
@ -8702,20 +8654,6 @@
|
|||
"value": {}
|
||||
}
|
||||
},
|
||||
"UpsertPermissionsQuery": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"tool_permissions"
|
||||
],
|
||||
"properties": {
|
||||
"tool_permissions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/ToolPermission"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Usage": {
|
||||
"type": "object",
|
||||
"description": "`input_tokens` is the total input including cache read/write tokens;\nthe cache fields are breakdown subsets of it. Parsers for providers\nthat report cache tokens separately from input (e.g. Anthropic,\nBedrock) must fold them into `input_tokens`.",
|
||||
|
|
|
|||
18
ui/desktop/src/acp/permissions.ts
Normal file
18
ui/desktop/src/acp/permissions.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import type { ToolListItem, ToolPermissionEntry, ToolPermissionLevel } from '@aaif/goose-sdk';
|
||||
import { getAcpClient } from './acpConnection';
|
||||
|
||||
export type { ToolListItem, ToolPermissionEntry, ToolPermissionLevel };
|
||||
|
||||
export async function listTools(sessionId: string, extensionName?: string): Promise<ToolListItem[]> {
|
||||
const client = await getAcpClient();
|
||||
const response = await client.goose.toolsList_unstable({
|
||||
sessionId,
|
||||
extensionName: extensionName ?? null,
|
||||
});
|
||||
return response.tools ?? [];
|
||||
}
|
||||
|
||||
export async function setToolPermissions(toolPermissions: ToolPermissionEntry[]): Promise<void> {
|
||||
const client = await getAcpClient();
|
||||
await client.goose.toolsPermissionsSet_unstable({ toolPermissions });
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -1605,11 +1605,6 @@ export type ToolInfo = {
|
|||
permission?: PermissionLevel | null;
|
||||
};
|
||||
|
||||
export type ToolPermission = {
|
||||
permission: PermissionLevel;
|
||||
tool_name: string;
|
||||
};
|
||||
|
||||
export type ToolRequest = {
|
||||
_meta?: {
|
||||
[key: string]: unknown;
|
||||
|
|
@ -1747,10 +1742,6 @@ export type UpsertConfigQuery = {
|
|||
value: unknown;
|
||||
};
|
||||
|
||||
export type UpsertPermissionsQuery = {
|
||||
tool_permissions: Array<ToolPermission>;
|
||||
};
|
||||
|
||||
/**
|
||||
* `input_tokens` is the total input including cache read/write tokens;
|
||||
* the cache fields are breakdown subsets of it. Parsers for providers
|
||||
|
|
@ -2402,29 +2393,6 @@ export type RemoveExtensionResponses = {
|
|||
|
||||
export type RemoveExtensionResponse = RemoveExtensionResponses[keyof RemoveExtensionResponses];
|
||||
|
||||
export type UpsertPermissionsData = {
|
||||
body: UpsertPermissionsQuery;
|
||||
path?: never;
|
||||
query?: never;
|
||||
url: '/config/permissions';
|
||||
};
|
||||
|
||||
export type UpsertPermissionsErrors = {
|
||||
/**
|
||||
* Invalid request
|
||||
*/
|
||||
400: unknown;
|
||||
};
|
||||
|
||||
export type UpsertPermissionsResponses = {
|
||||
/**
|
||||
* Permission update completed
|
||||
*/
|
||||
200: string;
|
||||
};
|
||||
|
||||
export type UpsertPermissionsResponse = UpsertPermissionsResponses[keyof UpsertPermissionsResponses];
|
||||
|
||||
export type GetPromptsData = {
|
||||
body?: never;
|
||||
path?: never;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { Button } from '../../ui/button';
|
||||
import { ChevronDownIcon, SlidersHorizontal, AlertCircle } from 'lucide-react';
|
||||
import { getTools, PermissionLevel, ToolInfo, upsertPermissions } from '../../../api';
|
||||
import { PermissionLevel } from '../../../api';
|
||||
import { listTools, setToolPermissions } from '../../../acp/permissions';
|
||||
import type { ToolListItem, ToolPermissionLevel } from '../../../acp/permissions';
|
||||
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '../../ui/dialog';
|
||||
import {
|
||||
DropdownMenu,
|
||||
|
|
@ -83,7 +85,7 @@ export default function PermissionModal({ extensionName, onClose }: PermissionMo
|
|||
const chatContext = useChatContext();
|
||||
const sessionId = chatContext?.chat.sessionId || '';
|
||||
|
||||
const [tools, setTools] = useState<ToolInfo[]>([]);
|
||||
const [tools, setTools] = useState<ToolListItem[]>([]);
|
||||
const [updatedPermissions, setUpdatedPermissions] = useState<Record<string, string>>({});
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [loadError, setLoadError] = useState<string | null>(null);
|
||||
|
|
@ -107,19 +109,12 @@ export default function PermissionModal({ extensionName, onClose }: PermissionMo
|
|||
setLoadError(null);
|
||||
|
||||
try {
|
||||
const response = await getTools({
|
||||
query: { extension_name: extensionName, session_id: sessionId },
|
||||
});
|
||||
if (response.error) {
|
||||
console.error('Failed to get tools:', response.error);
|
||||
setLoadError('fetch_failed');
|
||||
} else {
|
||||
const filteredTools = (response.data || []).filter(
|
||||
(tool: ToolInfo) =>
|
||||
tool.name !== 'platform__read_resource' && tool.name !== 'platform__list_resources'
|
||||
);
|
||||
setTools(filteredTools);
|
||||
}
|
||||
const fetched = await listTools(sessionId, extensionName);
|
||||
const filteredTools = fetched.filter(
|
||||
(tool) =>
|
||||
tool.name !== 'platform__read_resource' && tool.name !== 'platform__list_resources'
|
||||
);
|
||||
setTools(filteredTools);
|
||||
} catch (err) {
|
||||
console.error('Error fetching tools:', err);
|
||||
setLoadError('fetch_failed');
|
||||
|
|
@ -144,26 +139,18 @@ export default function PermissionModal({ extensionName, onClose }: PermissionMo
|
|||
|
||||
const handleSave = async () => {
|
||||
try {
|
||||
const payload = {
|
||||
tool_permissions: Object.entries(updatedPermissions).map(([toolName, permission]) => ({
|
||||
tool_name: toolName,
|
||||
permission: permission as PermissionLevel,
|
||||
})),
|
||||
};
|
||||
const toolPermissions = Object.entries(updatedPermissions).map(([toolName, permission]) => ({
|
||||
toolName,
|
||||
permission: permission as ToolPermissionLevel,
|
||||
}));
|
||||
|
||||
if (payload.tool_permissions.length === 0) {
|
||||
if (toolPermissions.length === 0) {
|
||||
onClose();
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await upsertPermissions({
|
||||
body: payload,
|
||||
});
|
||||
if (response.error) {
|
||||
console.error('Failed to save permissions:', response.error);
|
||||
} else {
|
||||
onClose();
|
||||
}
|
||||
await setToolPermissions(toolPermissions);
|
||||
onClose();
|
||||
} catch (err) {
|
||||
console.error('Error saving permissions:', err);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -144,6 +144,8 @@ import type {
|
|||
SetConfigExtensionEnabledRequest_unstable,
|
||||
SetRecipeSlashCommandRequest_unstable,
|
||||
SetSessionSystemPromptRequest_unstable,
|
||||
SetToolPermissionsRequest_unstable,
|
||||
SetToolPermissionsResponse_unstable,
|
||||
ShareSessionNostrRequest_unstable,
|
||||
ShareSessionNostrResponse_unstable,
|
||||
SteerSessionRequest_unstable,
|
||||
|
|
@ -214,6 +216,7 @@ import {
|
|||
zRunScheduleNowResponse_unstable,
|
||||
zSaveRecipeResponse_unstable,
|
||||
zScanRecipeResponse_unstable,
|
||||
zSetToolPermissionsResponse_unstable,
|
||||
zShareSessionNostrResponse_unstable,
|
||||
zSteerSessionResponse_unstable,
|
||||
zUpdateScheduleResponse_unstable,
|
||||
|
|
@ -245,6 +248,18 @@ export class GooseExtClient {
|
|||
return zGetToolsResponse_unstable.parse(raw) as GetToolsResponse_unstable;
|
||||
}
|
||||
|
||||
async toolsPermissionsSet_unstable(
|
||||
params: SetToolPermissionsRequest_unstable,
|
||||
): Promise<SetToolPermissionsResponse_unstable> {
|
||||
const raw = await this.conn.extMethod(
|
||||
"_goose/unstable/tools/permissions/set",
|
||||
params,
|
||||
);
|
||||
return zSetToolPermissionsResponse_unstable.parse(
|
||||
raw,
|
||||
) as SetToolPermissionsResponse_unstable;
|
||||
}
|
||||
|
||||
async toolsCall_unstable(
|
||||
params: GooseToolCallRequest_unstable,
|
||||
): Promise<GooseToolCallResponse_unstable> {
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -200,16 +200,53 @@ export type RemoveSessionExtensionRequest_unstable = {
|
|||
*/
|
||||
export type GetToolsRequest_unstable = {
|
||||
sessionId: string;
|
||||
/**
|
||||
* Filter tools to those belonging to this extension.
|
||||
*/
|
||||
extensionName?: string | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Tools response.
|
||||
*/
|
||||
export type GetToolsResponse_unstable = {
|
||||
/**
|
||||
* Array of tool info objects with `name`, `description`, `parameters`, and optional `permission`.
|
||||
*/
|
||||
tools: Array<unknown>;
|
||||
tools: Array<ToolListItem>;
|
||||
};
|
||||
|
||||
/**
|
||||
* A single tool item returned by the tools list endpoint.
|
||||
*/
|
||||
export type ToolListItem = {
|
||||
name: string;
|
||||
description: string;
|
||||
parameters: Array<string>;
|
||||
permission?: ToolPermissionLevel | null;
|
||||
inputSchema: unknown;
|
||||
outputSchema?: unknown;
|
||||
};
|
||||
|
||||
/**
|
||||
* Permission level for a tool.
|
||||
*/
|
||||
export type ToolPermissionLevel = 'always_allow' | 'ask_before' | 'never_allow';
|
||||
|
||||
/**
|
||||
* Set permission levels for one or more tools.
|
||||
*/
|
||||
export type SetToolPermissionsRequest_unstable = {
|
||||
toolPermissions: Array<ToolPermissionEntry>;
|
||||
};
|
||||
|
||||
/**
|
||||
* A single tool permission entry.
|
||||
*/
|
||||
export type ToolPermissionEntry = {
|
||||
toolName: string;
|
||||
permission: ToolPermissionLevel;
|
||||
};
|
||||
|
||||
export type SetToolPermissionsResponse_unstable = {
|
||||
[key: string]: unknown;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -2034,14 +2071,14 @@ export type RecipeParamsAction = 'submit' | 'cancel';
|
|||
export type ExtRequest = {
|
||||
id: string;
|
||||
method: string;
|
||||
params?: AddSessionExtensionRequest_unstable | RemoveSessionExtensionRequest_unstable | GetToolsRequest_unstable | GooseToolCallRequest_unstable | ReadResourceRequest_unstable | AppsListRequest_unstable | AppsExportRequest_unstable | AppsImportRequest_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 | ShareSessionNostrRequest_unstable | EncodeRecipeRequest_unstable | DecodeRecipeRequest_unstable | ScanRecipeRequest_unstable | ListRecipesRequest_unstable | DeleteRecipeRequest_unstable | ScheduleRecipeRequest_unstable | SetRecipeSlashCommandRequest_unstable | SaveRecipeRequest_unstable | ParseRecipeRequest_unstable | RecipeToYamlRequest_unstable | ListSchedulesRequest_unstable | ListScheduleSessionsRequest_unstable | CreateScheduleRequest_unstable | DeleteScheduleRequest_unstable | PauseScheduleRequest_unstable | UnpauseScheduleRequest_unstable | UpdateScheduleRequest_unstable | RunScheduleNowRequest_unstable | KillRunningJobRequest_unstable | InspectRunningJobRequest_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 | {
|
||||
params?: AddSessionExtensionRequest_unstable | RemoveSessionExtensionRequest_unstable | GetToolsRequest_unstable | SetToolPermissionsRequest_unstable | GooseToolCallRequest_unstable | ReadResourceRequest_unstable | AppsListRequest_unstable | AppsExportRequest_unstable | AppsImportRequest_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 | ShareSessionNostrRequest_unstable | EncodeRecipeRequest_unstable | DecodeRecipeRequest_unstable | ScanRecipeRequest_unstable | ListRecipesRequest_unstable | DeleteRecipeRequest_unstable | ScheduleRecipeRequest_unstable | SetRecipeSlashCommandRequest_unstable | SaveRecipeRequest_unstable | ParseRecipeRequest_unstable | RecipeToYamlRequest_unstable | ListSchedulesRequest_unstable | ListScheduleSessionsRequest_unstable | CreateScheduleRequest_unstable | DeleteScheduleRequest_unstable | PauseScheduleRequest_unstable | UnpauseScheduleRequest_unstable | UpdateScheduleRequest_unstable | RunScheduleNowRequest_unstable | KillRunningJobRequest_unstable | InspectRunningJobRequest_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 | AppsListResponse_unstable | AppsExportResponse_unstable | AppsImportResponse_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 | ShareSessionNostrResponse_unstable | EncodeRecipeResponse_unstable | DecodeRecipeResponse_unstable | ScanRecipeResponse_unstable | ListRecipesResponse_unstable | SaveRecipeResponse_unstable | ParseRecipeResponse_unstable | RecipeToYamlResponse_unstable | ListSchedulesResponse_unstable | ListScheduleSessionsResponse_unstable | CreateScheduleResponse_unstable | UpdateScheduleResponse_unstable | RunScheduleNowResponse_unstable | KillRunningJobResponse_unstable | InspectRunningJobResponse_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;
|
||||
result?: EmptyResponse | GetToolsResponse_unstable | SetToolPermissionsResponse_unstable | GooseToolCallResponse_unstable | ReadResourceResponse_unstable | AppsListResponse_unstable | AppsExportResponse_unstable | AppsImportResponse_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 | ShareSessionNostrResponse_unstable | EncodeRecipeResponse_unstable | DecodeRecipeResponse_unstable | ScanRecipeResponse_unstable | ListRecipesResponse_unstable | SaveRecipeResponse_unstable | ParseRecipeResponse_unstable | RecipeToYamlResponse_unstable | ListSchedulesResponse_unstable | ListScheduleSessionsResponse_unstable | CreateScheduleResponse_unstable | UpdateScheduleResponse_unstable | RunScheduleNowResponse_unstable | KillRunningJobResponse_unstable | InspectRunningJobResponse_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;
|
||||
|
|
|
|||
|
|
@ -167,16 +167,61 @@ export const zRemoveSessionExtensionRequest_unstable = z.object({
|
|||
* List all tools available in a session.
|
||||
*/
|
||||
export const zGetToolsRequest_unstable = z.object({
|
||||
sessionId: z.string()
|
||||
sessionId: z.string(),
|
||||
extensionName: z.union([
|
||||
z.string(),
|
||||
z.null()
|
||||
]).optional()
|
||||
});
|
||||
|
||||
/**
|
||||
* Permission level for a tool.
|
||||
*/
|
||||
export const zToolPermissionLevel = z.enum([
|
||||
'always_allow',
|
||||
'ask_before',
|
||||
'never_allow'
|
||||
]);
|
||||
|
||||
/**
|
||||
* A single tool item returned by the tools list endpoint.
|
||||
*/
|
||||
export const zToolListItem = z.object({
|
||||
name: z.string(),
|
||||
description: z.string(),
|
||||
parameters: z.array(z.string()),
|
||||
permission: z.union([
|
||||
zToolPermissionLevel,
|
||||
z.null()
|
||||
]).optional(),
|
||||
inputSchema: z.unknown(),
|
||||
outputSchema: z.unknown().optional()
|
||||
});
|
||||
|
||||
/**
|
||||
* Tools response.
|
||||
*/
|
||||
export const zGetToolsResponse_unstable = z.object({
|
||||
tools: z.array(z.unknown())
|
||||
tools: z.array(zToolListItem)
|
||||
});
|
||||
|
||||
/**
|
||||
* A single tool permission entry.
|
||||
*/
|
||||
export const zToolPermissionEntry = z.object({
|
||||
toolName: z.string(),
|
||||
permission: zToolPermissionLevel
|
||||
});
|
||||
|
||||
/**
|
||||
* Set permission levels for one or more tools.
|
||||
*/
|
||||
export const zSetToolPermissionsRequest_unstable = z.object({
|
||||
toolPermissions: z.array(zToolPermissionEntry)
|
||||
});
|
||||
|
||||
export const zSetToolPermissionsResponse_unstable = z.record(z.unknown());
|
||||
|
||||
/**
|
||||
* Call a tool from an extension.
|
||||
*/
|
||||
|
|
@ -2164,6 +2209,7 @@ export const zExtRequest = z.object({
|
|||
zAddSessionExtensionRequest_unstable,
|
||||
zRemoveSessionExtensionRequest_unstable,
|
||||
zGetToolsRequest_unstable,
|
||||
zSetToolPermissionsRequest_unstable,
|
||||
zGooseToolCallRequest_unstable,
|
||||
zReadResourceRequest_unstable,
|
||||
zAppsListRequest_unstable,
|
||||
|
|
@ -2264,6 +2310,7 @@ export const zExtResponse = z.union([
|
|||
z.union([
|
||||
zEmptyResponse,
|
||||
zGetToolsResponse_unstable,
|
||||
zSetToolPermissionsResponse_unstable,
|
||||
zGooseToolCallResponse_unstable,
|
||||
zReadResourceResponse_unstable,
|
||||
zAppsListResponse_unstable,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue