feat: hide worker threads from UI and disable spawn (#1624) (#1631)

This commit is contained in:
Steven Enamakel
2026-05-13 05:15:17 -07:00
committed by GitHub
parent 57c6d1be29
commit c63871e0b7
3 changed files with 49 additions and 16 deletions
+14 -4
View File
@@ -293,16 +293,22 @@ const Conversations = ({ variant = 'page', composer = 'text' }: ConversationsPro
// return;
// }
const threadStateForSelect = store.getState().thread;
if (data.threads.length > 0) {
// Worker/subagent threads are hidden from the conversation list
// (see tinyhumansai/openhuman#1624). Match the sidebar filter here so
// initial/resume selection can't auto-pick a hidden thread and leave
// the UI showing a thread that isn't in the list.
const visibleThreads = data.threads.filter(t => !t.parentThreadId);
if (visibleThreads.length > 0) {
// Prefer the thread the user was last viewing (persisted across
// reloads via redux-persist on the `thread` slice). Only fall
// through to "most recent" if that thread no longer exists
// server-side (deleted, purged, or different user).
// server-side (deleted, purged, or different user) — or is now
// hidden because it's a worker thread.
const persistedId = threadStateForSelect.selectedThreadId;
const resumeId =
persistedId && data.threads.some(t => t.id === persistedId)
persistedId && visibleThreads.some(t => t.id === persistedId)
? persistedId
: data.threads[0].id;
: visibleThreads[0].id;
dispatch(setSelectedThread(resumeId));
void dispatch(loadThreadMessages(resumeId));
} else {
@@ -940,6 +946,10 @@ const Conversations = ({ variant = 'page', composer = 'text' }: ConversationsPro
const filteredThreads = useMemo(() => {
const base = threads.filter(t => {
// Hide worker/subagent threads from the conversation list. They are
// currently surfaced inline inside the parent thread via WorkerThreadRefCard.
// A dedicated showcase is tracked in tinyhumansai/openhuman#1624.
if (t.parentThreadId) return false;
if (selectedLabel === 'all') return true;
return t.labels?.includes(selectedLabel);
});
@@ -128,7 +128,7 @@ impl Tool for SpawnSubagentTool {
},
"dedicated_thread": {
"type": "boolean",
"description": "Default `false`. Set `true` ONLY for long, complex sub-tasks where the parent thread should not be flooded with sub-agent output. The sub-agent's prompt and final summary land in a fresh worker-labeled thread the user can open from the thread list, and the parent receives a compact reference (worker thread id + brief summary) instead of the full transcript. Worker threads cannot themselves spawn another worker (sub-agents never see this tool), so this is a one-level-deep escape hatch."
"description": "Temporarily disabled (see tinyhumansai/openhuman#1624). Passing `true` causes this tool to return an explicit error. Omit the field or pass `false` until the worker-thread UI surface lands."
}
}
})
@@ -166,10 +166,25 @@ impl Tool for SpawnSubagentTool {
.map(|s| s.trim().to_string())
.filter(|s| !s.is_empty());
let dedicated_thread = args
// Worker-thread spawning is temporarily disabled until a proper UI
// showcase lands (see tinyhumansai/openhuman#1624). Return an
// explicit error when callers request a dedicated thread so the
// behaviour is observable rather than silently downgraded.
let dedicated_thread_requested = args
.get("dedicated_thread")
.and_then(|v| v.as_bool())
.unwrap_or(false);
if dedicated_thread_requested {
log::debug!(
"[spawn_subagent] dedicated_thread requested but temporarily \
disabled (see tinyhumansai/openhuman#1624); rejecting call"
);
return Ok(ToolResult::error(
"spawn_subagent: `dedicated_thread` is temporarily disabled \
(see tinyhumansai/openhuman#1624); retry without it.",
));
}
let dedicated_thread = false;
// ── Validation ─────────────────────────────────────────────────
if agent_id.is_empty() {
+18 -10
View File
@@ -29,7 +29,11 @@ use crate::openhuman::agent::harness::definition::{
};
use crate::openhuman::context::prompt::ConnectedIntegration;
use super::{ArchetypeDelegationTool, SkillDelegationTool, SpawnWorkerThreadTool, Tool};
// SpawnWorkerThreadTool import kept commented while the worker-thread spawn is
// temporarily disabled (see tinyhumansai/openhuman#1624).
#[allow(unused_imports)]
use super::SpawnWorkerThreadTool;
use super::{ArchetypeDelegationTool, SkillDelegationTool, Tool};
/// Synthesise the delegation tool list for an agent based on its
/// declarative `subagents` field.
@@ -66,9 +70,12 @@ pub fn collect_orchestrator_tools(
let mut tools: Vec<Box<dyn Tool>> = Vec::new();
// Orchestrator-only tool: spawn_worker_thread.
if definition.id == "orchestrator" {
tools.push(Box::new(SpawnWorkerThreadTool::new()));
}
// Temporarily disabled — worker threads do not yet have a proper UI
// showcase (see tinyhumansai/openhuman#1624). Re-enable once the
// dedicated worker-thread surface lands.
// if definition.id == "orchestrator" {
// tools.push(Box::new(SpawnWorkerThreadTool::new()));
// }
for entry in &definition.subagents {
match entry {
@@ -298,7 +305,9 @@ mod tests {
assert_eq!(
names,
vec![
"spawn_worker_thread", // orchestrator-only, prepended in collect_orchestrator_tools
// `spawn_worker_thread` is temporarily disabled — see
// tinyhumansai/openhuman#1624. Re-add the leading entry when
// the registration in `collect_orchestrator_tools` is restored.
"research", // researcher's delegate_name override
"delegate_archivist", // archivist has no delegate_name → default
"delegate_gmail",
@@ -329,10 +338,8 @@ mod tests {
let reg = registry_with_targets();
let tools = collect_orchestrator_tools(&orch, &reg, &[]);
let names: Vec<&str> = tools.iter().map(|t| t.name()).collect();
assert_eq!(
names,
vec!["spawn_worker_thread", "research", "delegate_archivist"]
);
// `spawn_worker_thread` is temporarily disabled — see #1624.
assert_eq!(names, vec!["research", "delegate_archivist"]);
}
/// An AgentId entry that points at an id not present in the registry
@@ -348,7 +355,8 @@ mod tests {
let reg = registry_with_targets();
let tools = collect_orchestrator_tools(&orch, &reg, &[]);
let names: Vec<&str> = tools.iter().map(|t| t.name()).collect();
assert_eq!(names, vec!["spawn_worker_thread", "research"]);
// `spawn_worker_thread` is temporarily disabled — see #1624.
assert_eq!(names, vec!["research"]);
}
/// An empty `subagents` list should produce zero tools — regular