mirror of
https://github.com/OpenHands/OpenHands.git
synced 2025-12-26 05:48:36 +08:00
feat(frontend): display plan content within the planner tab (#11658)
This commit is contained in:
parent
0e94833d5b
commit
a660321d55
80
frontend/src/components/features/markdown/headings.tsx
Normal file
80
frontend/src/components/features/markdown/headings.tsx
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { ExtraProps } from "react-markdown";
|
||||||
|
|
||||||
|
// Custom component to render <h1> in markdown
|
||||||
|
export function h1({
|
||||||
|
children,
|
||||||
|
}: React.ClassAttributes<HTMLHeadingElement> &
|
||||||
|
React.HTMLAttributes<HTMLHeadingElement> &
|
||||||
|
ExtraProps) {
|
||||||
|
return (
|
||||||
|
<h1 className="text-[32px] text-white font-bold leading-8 mb-4 mt-6 first:mt-0">
|
||||||
|
{children}
|
||||||
|
</h1>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom component to render <h2> in markdown
|
||||||
|
export function h2({
|
||||||
|
children,
|
||||||
|
}: React.ClassAttributes<HTMLHeadingElement> &
|
||||||
|
React.HTMLAttributes<HTMLHeadingElement> &
|
||||||
|
ExtraProps) {
|
||||||
|
return (
|
||||||
|
<h2 className="text-xl font-semibold leading-6 -tracking-[0.02em] text-white mb-3 mt-5 first:mt-0">
|
||||||
|
{children}
|
||||||
|
</h2>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom component to render <h3> in markdown
|
||||||
|
export function h3({
|
||||||
|
children,
|
||||||
|
}: React.ClassAttributes<HTMLHeadingElement> &
|
||||||
|
React.HTMLAttributes<HTMLHeadingElement> &
|
||||||
|
ExtraProps) {
|
||||||
|
return (
|
||||||
|
<h3 className="text-lg font-semibold text-white mb-2 mt-4 first:mt-0">
|
||||||
|
{children}
|
||||||
|
</h3>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom component to render <h4> in markdown
|
||||||
|
export function h4({
|
||||||
|
children,
|
||||||
|
}: React.ClassAttributes<HTMLHeadingElement> &
|
||||||
|
React.HTMLAttributes<HTMLHeadingElement> &
|
||||||
|
ExtraProps) {
|
||||||
|
return (
|
||||||
|
<h4 className="text-base font-semibold text-white mb-2 mt-4 first:mt-0">
|
||||||
|
{children}
|
||||||
|
</h4>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom component to render <h5> in markdown
|
||||||
|
export function h5({
|
||||||
|
children,
|
||||||
|
}: React.ClassAttributes<HTMLHeadingElement> &
|
||||||
|
React.HTMLAttributes<HTMLHeadingElement> &
|
||||||
|
ExtraProps) {
|
||||||
|
return (
|
||||||
|
<h5 className="text-sm font-semibold text-white mb-2 mt-3 first:mt-0">
|
||||||
|
{children}
|
||||||
|
</h5>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom component to render <h6> in markdown
|
||||||
|
export function h6({
|
||||||
|
children,
|
||||||
|
}: React.ClassAttributes<HTMLHeadingElement> &
|
||||||
|
React.HTMLAttributes<HTMLHeadingElement> &
|
||||||
|
ExtraProps) {
|
||||||
|
return (
|
||||||
|
<h6 className="text-sm font-medium text-gray-300 mb-2 mt-3 first:mt-0">
|
||||||
|
{children}
|
||||||
|
</h6>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -471,12 +471,12 @@ export enum I18nKey {
|
|||||||
PROJECT_MENU_DETAILS_PLACEHOLDER$CONNECT_TO_GITHUB = "PROJECT_MENU_DETAILS_PLACEHOLDER$CONNECT_TO_GITHUB",
|
PROJECT_MENU_DETAILS_PLACEHOLDER$CONNECT_TO_GITHUB = "PROJECT_MENU_DETAILS_PLACEHOLDER$CONNECT_TO_GITHUB",
|
||||||
PROJECT_MENU_DETAILS_PLACEHOLDER$CONNECTED = "PROJECT_MENU_DETAILS_PLACEHOLDER$CONNECTED",
|
PROJECT_MENU_DETAILS_PLACEHOLDER$CONNECTED = "PROJECT_MENU_DETAILS_PLACEHOLDER$CONNECTED",
|
||||||
PROJECT_MENU_DETAILS$AGO_LABEL = "PROJECT_MENU_DETAILS$AGO_LABEL",
|
PROJECT_MENU_DETAILS$AGO_LABEL = "PROJECT_MENU_DETAILS$AGO_LABEL",
|
||||||
STATUS$ERROR = "STATUS$ERROR",
|
|
||||||
STATUS$ERROR_LLM_AUTHENTICATION = "STATUS$ERROR_LLM_AUTHENTICATION",
|
STATUS$ERROR_LLM_AUTHENTICATION = "STATUS$ERROR_LLM_AUTHENTICATION",
|
||||||
STATUS$ERROR_LLM_SERVICE_UNAVAILABLE = "STATUS$ERROR_LLM_SERVICE_UNAVAILABLE",
|
STATUS$ERROR_LLM_SERVICE_UNAVAILABLE = "STATUS$ERROR_LLM_SERVICE_UNAVAILABLE",
|
||||||
STATUS$ERROR_LLM_INTERNAL_SERVER_ERROR = "STATUS$ERROR_LLM_INTERNAL_SERVER_ERROR",
|
STATUS$ERROR_LLM_INTERNAL_SERVER_ERROR = "STATUS$ERROR_LLM_INTERNAL_SERVER_ERROR",
|
||||||
STATUS$ERROR_LLM_OUT_OF_CREDITS = "STATUS$ERROR_LLM_OUT_OF_CREDITS",
|
STATUS$ERROR_LLM_OUT_OF_CREDITS = "STATUS$ERROR_LLM_OUT_OF_CREDITS",
|
||||||
STATUS$ERROR_LLM_CONTENT_POLICY_VIOLATION = "STATUS$ERROR_LLM_CONTENT_POLICY_VIOLATION",
|
STATUS$ERROR_LLM_CONTENT_POLICY_VIOLATION = "STATUS$ERROR_LLM_CONTENT_POLICY_VIOLATION",
|
||||||
|
STATUS$ERROR = "STATUS$ERROR",
|
||||||
STATUS$ERROR_RUNTIME_DISCONNECTED = "STATUS$ERROR_RUNTIME_DISCONNECTED",
|
STATUS$ERROR_RUNTIME_DISCONNECTED = "STATUS$ERROR_RUNTIME_DISCONNECTED",
|
||||||
STATUS$ERROR_MEMORY = "STATUS$ERROR_MEMORY",
|
STATUS$ERROR_MEMORY = "STATUS$ERROR_MEMORY",
|
||||||
STATUS$GIT_PROVIDER_AUTHENTICATION_ERROR = "STATUS$GIT_PROVIDER_AUTHENTICATION_ERROR",
|
STATUS$GIT_PROVIDER_AUTHENTICATION_ERROR = "STATUS$GIT_PROVIDER_AUTHENTICATION_ERROR",
|
||||||
|
|||||||
@ -1,13 +1,52 @@
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import Markdown from "react-markdown";
|
||||||
|
import remarkGfm from "remark-gfm";
|
||||||
|
import remarkBreaks from "remark-breaks";
|
||||||
import { I18nKey } from "#/i18n/declaration";
|
import { I18nKey } from "#/i18n/declaration";
|
||||||
import LessonPlanIcon from "#/icons/lesson-plan.svg?react";
|
import LessonPlanIcon from "#/icons/lesson-plan.svg?react";
|
||||||
import { useConversationStore } from "#/state/conversation-store";
|
import { useConversationStore } from "#/state/conversation-store";
|
||||||
|
import { code } from "#/components/features/markdown/code";
|
||||||
|
import { ul, ol } from "#/components/features/markdown/list";
|
||||||
|
import { paragraph } from "#/components/features/markdown/paragraph";
|
||||||
|
import { anchor } from "#/components/features/markdown/anchor";
|
||||||
|
import {
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6,
|
||||||
|
} from "#/components/features/markdown/headings";
|
||||||
|
|
||||||
function PlannerTab() {
|
function PlannerTab() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const setConversationMode = useConversationStore(
|
|
||||||
(state) => state.setConversationMode,
|
const { planContent, setConversationMode } = useConversationStore();
|
||||||
);
|
|
||||||
|
if (planContent) {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col w-full h-full p-4 overflow-auto">
|
||||||
|
<Markdown
|
||||||
|
components={{
|
||||||
|
code,
|
||||||
|
ul,
|
||||||
|
ol,
|
||||||
|
a: anchor,
|
||||||
|
p: paragraph,
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6,
|
||||||
|
}}
|
||||||
|
remarkPlugins={[remarkGfm, remarkBreaks]}
|
||||||
|
>
|
||||||
|
{planContent}
|
||||||
|
</Markdown>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col items-center justify-center w-full h-full p-10">
|
<div className="flex flex-col items-center justify-center w-full h-full p-10">
|
||||||
|
|||||||
@ -28,6 +28,7 @@ interface ConversationState {
|
|||||||
submittedMessage: string | null;
|
submittedMessage: string | null;
|
||||||
shouldHideSuggestions: boolean; // New state to hide suggestions when input expands
|
shouldHideSuggestions: boolean; // New state to hide suggestions when input expands
|
||||||
hasRightPanelToggled: boolean;
|
hasRightPanelToggled: boolean;
|
||||||
|
planContent: string | null;
|
||||||
conversationMode: ConversationMode;
|
conversationMode: ConversationMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,6 +79,91 @@ export const useConversationStore = create<ConversationStore>()(
|
|||||||
submittedMessage: null,
|
submittedMessage: null,
|
||||||
shouldHideSuggestions: false,
|
shouldHideSuggestions: false,
|
||||||
hasRightPanelToggled: true,
|
hasRightPanelToggled: true,
|
||||||
|
planContent: `
|
||||||
|
# Improve Developer Onboarding and Examples
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Based on the analysis of Browser-Use's current documentation and examples, this plan addresses gaps in developer onboarding by creating a progressive learning path, troubleshooting resources, and practical examples that address real-world scenarios (like the LM Studio/local LLM integration issues encountered).
|
||||||
|
|
||||||
|
## Current State Analysis
|
||||||
|
|
||||||
|
**Strengths:**
|
||||||
|
|
||||||
|
- Good quickstart documentation in \`docs/quickstart.mdx\`
|
||||||
|
- Extensive examples across multiple categories (60+ example files)
|
||||||
|
- Well-structured docs with multiple LLM provider examples
|
||||||
|
- Active community support via Discord
|
||||||
|
|
||||||
|
**Gaps Identified:**
|
||||||
|
|
||||||
|
- No progressive tutorial series that builds complexity gradually
|
||||||
|
- Limited troubleshooting documentation for common issues
|
||||||
|
- Sparse comments in example files explaining what's happening
|
||||||
|
- Local LLM setup (Ollama/LM Studio) not prominently featured
|
||||||
|
- No "first 10 minutes" success path
|
||||||
|
- Missing visual/conceptual architecture guides for beginners
|
||||||
|
- Error messages don't always point to solutions
|
||||||
|
|
||||||
|
## Proposed Improvements
|
||||||
|
|
||||||
|
### 1. Create Interactive Tutorial Series (\`examples/tutorials/\`)
|
||||||
|
|
||||||
|
**New folder structure:**
|
||||||
|
|
||||||
|
\`\`\`
|
||||||
|
examples/tutorials/
|
||||||
|
├── README.md # Tutorial overview and prerequisites
|
||||||
|
├── 00_hello_world.py # Absolute minimal example
|
||||||
|
├── 01_your_first_search.py # Basic search with detailed comments
|
||||||
|
├── 02_understanding_actions.py # How actions work
|
||||||
|
├── 03_data_extraction_basics.py # Extract data step-by-step
|
||||||
|
├── 04_error_handling.py # Common errors and solutions
|
||||||
|
├── 05_custom_tools_intro.py # First custom tool
|
||||||
|
├── 06_local_llm_setup.py # Ollama/LM Studio complete guide
|
||||||
|
└── 07_debugging_tips.py # Debugging strategies
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
**Key Features:**
|
||||||
|
|
||||||
|
- Each file 50–80 lines max
|
||||||
|
- Extensive inline comments explaining every concept
|
||||||
|
- Clear learning objectives at the top of each file
|
||||||
|
- "What you'll learn" and "Prerequisites" sections
|
||||||
|
- Common pitfalls highlighted
|
||||||
|
- Expected output shown in comments
|
||||||
|
|
||||||
|
### 2. Troubleshooting Guide (\`docs/troubleshooting.mdx\`)
|
||||||
|
|
||||||
|
**Sections:**
|
||||||
|
|
||||||
|
- Installation issues (Chromium, dependencies, virtual environments)
|
||||||
|
- LLM provider connection errors (API keys, timeouts, rate limits)
|
||||||
|
- Local LLM setup (Ollama vs LM Studio, model compatibility)
|
||||||
|
- Browser automation issues (element not found, timeout errors)
|
||||||
|
- Common error messages with solutions
|
||||||
|
- Performance optimization tips
|
||||||
|
- When to ask for help (Discord/GitHub)
|
||||||
|
|
||||||
|
**Format:**
|
||||||
|
|
||||||
|
**Error: "LLM call timed out after 60 seconds"**
|
||||||
|
|
||||||
|
**What it means:**
|
||||||
|
The model took too long to respond
|
||||||
|
|
||||||
|
**Common causes:**
|
||||||
|
|
||||||
|
1. Model is too slow for the task
|
||||||
|
2. LM Studio/Ollama not responding properly
|
||||||
|
3. Complex page overwhelming the model
|
||||||
|
|
||||||
|
**Solutions:**
|
||||||
|
|
||||||
|
- Use flash_mode for faster execution
|
||||||
|
- Try a faster model (Gemini Flash, GPT-4 Turbo Mini)
|
||||||
|
- Simplify the task
|
||||||
|
- Check model server logs`,
|
||||||
conversationMode: "code",
|
conversationMode: "code",
|
||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user