Implement local sub-agent execution for OSS/Bedrock mode
- Fix start_agent tool mapping: route to Tool::StartAgent instead of dead-end Tool::Subagent so tool calls become executable actions - Block start_agent until child finishes: parent waits for child conversation to complete and receives full output as tool result - Fix tool result delivery: add StartAgent/StartAgentV2 cases to extract_tool_result_content so the model actually sees agent output - Support parallel agent spawning: change StartAgent action phase from Serial to Parallel, and track multiple pending agents via Vec - Mark child conversations as Success on EndTurn: emit ConversationStatus::Success when a child stream ends with no actions - Skip orchestration SSE in local mode: prevent app freeze from trying to connect to non-existent server - Remove send_message_to_agent and suggest_next_prompt from tool list: these require server infrastructure that doesn't exist in OSS mode - Add "Waiting for sub-agents..." status message while agents process - Fix child agent pane close: actually dismiss instead of re-hiding, track dismissed IDs to prevent re-creation on restart - Fix cache_miss_tokens calculation and show per-block cache stats - Add [tool-debug] logging throughout tool invocation pipeline Bump version to 1.6.0. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
17ecf67970
commit
a309006458
@@ -465,6 +465,16 @@ impl BlocklistAIActionModel {
|
||||
conversation_id: AIConversationId,
|
||||
ctx: &mut ModelContext<Self>,
|
||||
) {
|
||||
let pending_count = self
|
||||
.pending_actions
|
||||
.get(&conversation_id)
|
||||
.map(|q| q.len())
|
||||
.unwrap_or(0);
|
||||
log::info!(
|
||||
"[tool-debug] try_to_execute_available_actions: conversation={:?}, pending_count={}",
|
||||
conversation_id,
|
||||
pending_count
|
||||
);
|
||||
loop {
|
||||
let Some(front_action) = self
|
||||
.pending_actions
|
||||
@@ -472,9 +482,16 @@ impl BlocklistAIActionModel {
|
||||
.and_then(|queue| queue.front())
|
||||
.cloned()
|
||||
else {
|
||||
log::info!("[tool-debug] try_to_execute_available_actions: no more pending actions");
|
||||
return;
|
||||
};
|
||||
|
||||
log::info!(
|
||||
"[tool-debug] try_to_execute_available_actions: trying action id={:?}, type={:?}",
|
||||
front_action.id,
|
||||
std::mem::discriminant(&front_action.action)
|
||||
);
|
||||
|
||||
if let Some(current_phase) = self.action_execution_phase(conversation_id) {
|
||||
if !self.can_start_action_in_current_phase(
|
||||
&front_action,
|
||||
@@ -482,6 +499,10 @@ impl BlocklistAIActionModel {
|
||||
current_phase,
|
||||
ctx,
|
||||
) {
|
||||
log::info!(
|
||||
"[tool-debug] try_to_execute_available_actions: cannot start in current phase {:?}",
|
||||
current_phase
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -489,15 +510,22 @@ impl BlocklistAIActionModel {
|
||||
let Some(result) =
|
||||
self.start_pending_action_by_id(&front_action.id, conversation_id, false, ctx)
|
||||
else {
|
||||
log::info!("[tool-debug] try_to_execute_available_actions: start_pending_action_by_id returned None (blocked)");
|
||||
return;
|
||||
};
|
||||
|
||||
log::info!(
|
||||
"[tool-debug] try_to_execute_available_actions: action started, result={:?}",
|
||||
std::mem::discriminant(&result)
|
||||
);
|
||||
|
||||
if matches!(
|
||||
result,
|
||||
StartedAction::Async {
|
||||
phase: RunningActionPhase::Serial
|
||||
}
|
||||
) {
|
||||
log::info!("[tool-debug] try_to_execute_available_actions: serial async action, stopping loop");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -853,6 +881,19 @@ impl BlocklistAIActionModel {
|
||||
conversation_id: AIConversationId,
|
||||
ctx: &mut ModelContext<Self>,
|
||||
) {
|
||||
log::info!(
|
||||
"[tool-debug] queue_actions: queuing {} actions for conversation {:?}",
|
||||
actions.len(),
|
||||
conversation_id
|
||||
);
|
||||
for (i, action) in actions.iter().enumerate() {
|
||||
log::info!(
|
||||
"[tool-debug] queue_actions: [{}] id={:?}, type={:?}",
|
||||
i,
|
||||
action.id,
|
||||
std::mem::discriminant(&action.action)
|
||||
);
|
||||
}
|
||||
self.action_order.insert(
|
||||
conversation_id,
|
||||
actions
|
||||
@@ -1135,6 +1176,12 @@ impl BlocklistAIActionModel {
|
||||
cancellation_reason: Option<CancellationReason>,
|
||||
ctx: &mut ModelContext<Self>,
|
||||
) {
|
||||
log::info!(
|
||||
"[tool-debug] handle_action_result: action_id={:?}, result_type={:?}, cancellation={:?}",
|
||||
action_result.id,
|
||||
std::mem::discriminant(&action_result.result),
|
||||
cancellation_reason
|
||||
);
|
||||
let should_remove_entry =
|
||||
self.running_actions
|
||||
.get_mut(&conversation_id)
|
||||
|
||||
Reference in New Issue
Block a user