Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions desktop/scripts/check-file-sizes.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@ const overrides = new Map([
["src/shared/api/tauri.ts", 1100], // remote agent provider API bindings + canvas API functions
["src-tauri/src/lib.rs", 550], // sprout-media:// proxy now forwards Range headers + propagates Content-Range/Accept-Ranges for video seeking
["src-tauri/src/commands/media.rs", 720], // ffmpeg video transcode + poster frame extraction + run_ffmpeg_with_timeout (find_ffmpeg, is_video_file, transcode_to_mp4, extract_poster_frame, transcode_and_extract_poster) + spawn_blocking wrappers + tests
["src-tauri/src/commands/agents.rs", 849], // remote agent lifecycle routing (local + provider branches) + scope enforcement; rustfmt adds line breaks around long tuple/closure blocks
["src-tauri/src/commands/agents.rs", 860], // remote agent lifecycle routing (local + provider branches) + scope enforcement + mcp_toolsets field; rustfmt adds line breaks around long tuple/closure blocks
["src-tauri/src/managed_agents/runtime.rs", 650], // KNOWN_AGENT_BINARIES const + process_belongs_to_us FFI (macOS proc_name + Linux /proc/comm) + terminate_process + start/stop/sync lifecycle
["src-tauri/src/managed_agents/backend.rs", 530], // provider IPC, validation, discovery, binary resolution + tests
["src/features/agents/hooks.ts", 520], // agent query/mutation surface now includes built-in persona library activation
["src/features/agents/ui/AgentsView.tsx", 850], // remote agent lifecycle controls + persona/team management + built-in catalog/library state orchestration
["src/features/agents/ui/CreateAgentDialog.tsx", 685], // provider selector + config form + schema-typed config coercion + required field validation + locked scopes
["src/features/channels/ui/AddChannelBotDialog.tsx", 640], // provider mode: Run on selector, trust warning, probe effect, single-agent enforcement, provider warnings display
["src/shared/api/types.ts", 530], // persona provider/model fields + forum types + workflow type re-exports + ephemeral channel TTL fields
["src/shared/api/types.ts", 535], // persona provider/model fields + forum types + workflow type re-exports + ephemeral channel TTL fields + mcpToolsets
]);

async function walkFiles(directory) {
Expand Down
7 changes: 7 additions & 0 deletions desktop/src-tauri/src/commands/agent_models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,13 @@ pub fn update_managed_agent(
if let Some(prompt_update) = input.system_prompt {
record.system_prompt = prompt_update;
}
if let Some(toolsets_update) = input.mcp_toolsets {
record.mcp_toolsets = toolsets_update
.as_deref()
.map(str::trim)
.filter(|v| !v.is_empty())
.map(str::to_string);
}
record.updated_at = now_iso();

save_managed_agents(&app, &records)?;
Expand Down
6 changes: 6 additions & 0 deletions desktop/src-tauri/src/commands/agents.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,12 @@ pub async fn create_managed_agent(
.map(str::trim)
.filter(|value| !value.is_empty())
.map(str::to_string),
mcp_toolsets: input
.mcp_toolsets
.as_deref()
.map(str::trim)
.filter(|value| !value.is_empty())
.map(str::to_string),
// Provider agents don't auto-start with the desktop — they're
// managed externally. Force false to avoid persisting a flag the
// app will never honor.
Expand Down
6 changes: 6 additions & 0 deletions desktop/src-tauri/src/managed_agents/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,7 @@ pub fn build_managed_agent_summary(
parallelism: record.parallelism,
system_prompt: record.system_prompt.clone(),
model: record.model.clone(),
mcp_toolsets: record.mcp_toolsets.clone(),
has_api_token: record.api_token.is_some(),
backend: record.backend.clone(),
backend_agent_id: record.backend_agent_id.clone(),
Expand Down Expand Up @@ -526,6 +527,11 @@ pub fn start_managed_agent_process(
} else {
command.env_remove("SPROUT_ACP_MODEL");
}
if let Some(toolsets) = &record.mcp_toolsets {
command.env("SPROUT_TOOLSETS", toolsets);
} else {
command.env_remove("SPROUT_TOOLSETS");
}
command.env_remove("SPROUT_ACP_PRIVATE_KEY");
command.env_remove("SPROUT_ACP_API_TOKEN");

Expand Down
8 changes: 8 additions & 0 deletions desktop/src-tauri/src/managed_agents/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ pub struct ManagedAgentRecord {
/// creation by matching this ID against the fresh session/new response.
#[serde(default)]
pub model: Option<String>,
/// Comma-separated toolset string forwarded as SPROUT_TOOLSETS to the MCP subprocess.
/// When None, the MCP server uses its own default ("default" toolset).
#[serde(default)]
pub mcp_toolsets: Option<String>,
#[serde(default = "default_start_on_app_launch")]
pub start_on_app_launch: bool,
#[serde(default)]
Expand Down Expand Up @@ -117,6 +121,7 @@ pub struct ManagedAgentSummary {
pub parallelism: u32,
pub system_prompt: Option<String>,
pub model: Option<String>,
pub mcp_toolsets: Option<String>,
pub has_api_token: bool,
pub backend: BackendKind,
pub backend_agent_id: Option<String>,
Expand Down Expand Up @@ -151,6 +156,7 @@ pub struct CreateManagedAgentRequest {
pub system_prompt: Option<String>,
pub avatar_url: Option<String>,
pub model: Option<String>,
pub mcp_toolsets: Option<String>,
#[serde(default)]
pub mint_token: bool,
#[serde(default)]
Expand Down Expand Up @@ -271,6 +277,8 @@ pub struct UpdateManagedAgentRequest {
pub model: Option<Option<String>>,
#[serde(default)]
pub system_prompt: Option<Option<String>>,
#[serde(default)]
pub mcp_toolsets: Option<Option<String>>,
}

/// Response from `get_agent_models` — normalized model info for the frontend.
Expand Down
5 changes: 5 additions & 0 deletions desktop/src/features/agents/ui/CreateAgentDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export function CreateAgentDialog({
const [agentCommand, setAgentCommand] = React.useState("goose");
const [agentArgs, setAgentArgs] = React.useState("acp");
const [mcpCommand, setMcpCommand] = React.useState("sprout-mcp-server");
const [mcpToolsets, setMcpToolsets] = React.useState("");
const prereqsQuery = useManagedAgentPrereqsQuery(acpCommand, mcpCommand);
const [name, setName] = React.useState("");
const [relayUrl, setRelayUrl] = React.useState("");
Expand Down Expand Up @@ -213,6 +214,7 @@ export function CreateAgentDialog({
setAgentCommand("goose");
setAgentArgs("acp");
setMcpCommand("sprout-mcp-server");
setMcpToolsets("");
setTurnTimeoutSeconds("320");
setParallelism("3");
setSystemPrompt("");
Expand Down Expand Up @@ -355,6 +357,7 @@ export function CreateAgentDialog({
.map((value) => value.trim())
.filter((value) => value.length > 0),
mcpCommand: mcpCommand.trim() || undefined,
mcpToolsets: mcpToolsets.trim() || undefined,
turnTimeoutSeconds:
Number.parseInt(turnTimeoutSeconds, 10) > 0
? Number.parseInt(turnTimeoutSeconds, 10)
Expand Down Expand Up @@ -530,11 +533,13 @@ export function CreateAgentDialog({
agentArgs={agentArgs}
agentCommand={agentCommand}
mcpCommand={mcpCommand}
mcpToolsets={mcpToolsets}
onParallelismChange={setParallelism}
onAcpCommandChange={setAcpCommand}
onAgentArgsChange={setAgentArgs}
onAgentCommandChange={setAgentCommand}
onMcpCommandChange={setMcpCommand}
onMcpToolsetsChange={setMcpToolsets}
onRelayUrlChange={setRelayUrl}
onSystemPromptChange={setSystemPrompt}
onTurnTimeoutChange={setTurnTimeoutSeconds}
Expand Down
21 changes: 21 additions & 0 deletions desktop/src/features/agents/ui/CreateAgentDialogSections.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ export function CreateAgentRuntimeFields({
agentArgs,
agentCommand,
mcpCommand,
mcpToolsets,
parallelism,
relayUrl,
selectedProviderId,
Expand All @@ -109,6 +110,7 @@ export function CreateAgentRuntimeFields({
onAgentArgsChange,
onAgentCommandChange,
onMcpCommandChange,
onMcpToolsetsChange,
onParallelismChange,
onRelayUrlChange,
onSystemPromptChange,
Expand All @@ -118,6 +120,7 @@ export function CreateAgentRuntimeFields({
agentArgs: string;
agentCommand: string;
mcpCommand: string;
mcpToolsets: string;
parallelism: string;
relayUrl: string;
selectedProviderId: string;
Expand All @@ -127,6 +130,7 @@ export function CreateAgentRuntimeFields({
onAgentArgsChange: (value: string) => void;
onAgentCommandChange: (value: string) => void;
onMcpCommandChange: (value: string) => void;
onMcpToolsetsChange: (value: string) => void;
onParallelismChange: (value: string) => void;
onRelayUrlChange: (value: string) => void;
onSystemPromptChange: (value: string) => void;
Expand Down Expand Up @@ -280,6 +284,23 @@ export function CreateAgentRuntimeFields({
</div>
</div>

<div className="space-y-1.5">
<label className="text-sm font-medium" htmlFor="agent-mcp-toolsets">
MCP toolsets
</label>
<Input
id="agent-mcp-toolsets"
onChange={(event) => onMcpToolsetsChange(event.target.value)}
placeholder="default"
value={mcpToolsets}
/>
<p className="text-xs text-muted-foreground">
Comma-separated list of toolsets to expose via SPROUT_TOOLSETS.
Available: default, channel_admin, dms, canvas, workflow_admin,
identity, forums, social. Leave blank for the default toolset only.
</p>
</div>

<div className="space-y-1.5">
<label className="text-sm font-medium" htmlFor="agent-system-prompt">
System prompt override
Expand Down
3 changes: 3 additions & 0 deletions desktop/src/shared/api/tauri.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ export type RawManagedAgent = {
parallelism: number;
system_prompt: string | null;
model: string | null;
mcp_toolsets: string | null;
has_api_token: boolean;
status: ManagedAgent["status"];
pid: number | null;
Expand Down Expand Up @@ -831,6 +832,7 @@ export function fromRawManagedAgent(agent: RawManagedAgent): ManagedAgent {
parallelism: agent.parallelism,
systemPrompt: agent.system_prompt,
model: agent.model,
mcpToolsets: agent.mcp_toolsets,
hasApiToken: agent.has_api_token,
status: agent.status,
pid: agent.pid,
Expand Down Expand Up @@ -927,6 +929,7 @@ export async function createManagedAgent(input: CreateManagedAgentInput) {
agentCommand: input.agentCommand,
agentArgs: input.agentArgs,
mcpCommand: input.mcpCommand,
mcpToolsets: input.mcpToolsets,
turnTimeoutSeconds: input.turnTimeoutSeconds,
idleTimeoutSeconds: input.idleTimeoutSeconds,
maxTurnDurationSeconds: input.maxTurnDurationSeconds,
Expand Down
3 changes: 3 additions & 0 deletions desktop/src/shared/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ export type ManagedAgent = {
parallelism: number;
systemPrompt: string | null;
model: string | null;
mcpToolsets: string | null;
hasApiToken: boolean;
status: "running" | "stopped" | "deployed" | "not_deployed";
pid: number | null;
Expand Down Expand Up @@ -337,6 +338,7 @@ export type CreateManagedAgentInput = {
systemPrompt?: string;
avatarUrl?: string;
model?: string;
mcpToolsets?: string;
mintToken?: boolean;
tokenScopes?: TokenScope[];
tokenName?: string;
Expand Down Expand Up @@ -407,6 +409,7 @@ export type UpdateManagedAgentInput = {
name?: string;
model?: string | null;
systemPrompt?: string | null;
mcpToolsets?: string | null;
};
export type AgentPersona = {
id: string;
Expand Down
Loading