(
&self,
agent_run_id: &str,
ctx: &InternalRunContext<'_>,
token_sink: &S,
)
| 576 | } |
| 577 | |
| 578 | async fn execute_agent<S: TokenSink + Sync>( |
| 579 | &self, |
| 580 | agent_run_id: &str, |
| 581 | ctx: &InternalRunContext<'_>, |
| 582 | token_sink: &S, |
| 583 | ) -> AppResult<String> { |
| 584 | let system_prompt = get_prompt(ctx.agent_type).ok_or_else(|| { |
| 585 | AppError::Validation(format!("Unknown agent type for prompt lookup: {}", ctx.agent_type)) |
| 586 | })?; |
| 587 | |
| 588 | let provider = provider_service::get_provider_for_chat(&self.db, ctx.provider_id).await?; |
| 589 | |
| 590 | // Pre-flight: check API key is configured (except for local providers like Ollama) |
| 591 | if provider.provider_type != "ollama" |
| 592 | && provider |
| 593 | .api_key |
| 594 | .as_deref() |
| 595 | .is_none_or(|k| k.trim().is_empty()) |
| 596 | { |
| 597 | return Err(AppError::Validation(format!( |
| 598 | "API key not configured for '{}'. Go to Settings → Providers and enter your API key.", |
| 599 | provider.name |
| 600 | ))); |
| 601 | } |
| 602 | |
| 603 | let model = ctx.model_id.unwrap_or(&provider.model); |
| 604 | let tool_executor = ToolExecutor::new(PathBuf::from(ctx.project_path)); |
| 605 | |
| 606 | // Solusi 1: Lazy PREVIEW_GUIDE — only inject full guide when user asks for visuals |
| 607 | let system_content = if ctx.flux_enabled { |
| 608 | if needs_full_preview_guide(ctx.task) { |
| 609 | format!("{}\n\n{}\n\n{}", system_prompt, LANGUAGE_GUARD, PREVIEW_GUIDE) |
| 610 | } else { |
| 611 | // Mini hint only (~50 tokens vs ~4500) |
| 612 | format!("{}\n\n{}\n\n{}", system_prompt, LANGUAGE_GUARD, PREVIEW_HINT) |
| 613 | } |
| 614 | } else { |
| 615 | format!("{}\n\n{}", system_prompt, LANGUAGE_GUARD) |
| 616 | }; |
| 617 | |
| 618 | // Load conversation history for context |
| 619 | let history = self.load_conversation_history(ctx.session_id).await?; |
| 620 | |
| 621 | // Build messages: system + history (excluding last user msg) + current task |
| 622 | let mut messages = vec![ConversationMessage::system(&system_content)]; |
| 623 | |
| 624 | // Add history but skip the last user message (it's the current task we're about to add) |
| 625 | if history.len() > 1 { |
| 626 | let history_without_last = &history[..history.len() - 1]; |
| 627 | messages.extend_from_slice(history_without_last); |
| 628 | } |
| 629 | |
| 630 | messages.push(ConversationMessage::user(ctx.task)); |
| 631 | |
| 632 | let mut output = self |
| 633 | .run_react_loop( |
| 634 | &provider, |
| 635 | model, |
no test coverage detected