Skip to content

Commit

Permalink
Merge branch 'All-Hands-AI:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
RainRat authored Dec 16, 2024
2 parents 9f3b623 + d6a2c4b commit 206f37a
Show file tree
Hide file tree
Showing 15 changed files with 361 additions and 353 deletions.
4 changes: 2 additions & 2 deletions docs/modules/usage/micro-agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Micro-agents are defined in markdown files under the `openhands/agenthub/codeact
## Available Micro-Agents

### GitHub Agent
**File**: `github.md`
**File**: `github.md`
**Triggers**: `github`, `git`

The GitHub agent specializes in GitHub API interactions and repository management. It:
Expand All @@ -30,7 +30,7 @@ Key features:
- API-first approach for GitHub operations

### NPM Agent
**File**: `npm.md`
**File**: `npm.md`
**Triggers**: `npm`

Specializes in handling npm package management with specific focus on:
Expand Down
2 changes: 1 addition & 1 deletion docs/modules/usage/prompting-best-practices.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ When working with a customized repository:

Example customized prompt:
```
Add a new task completion feature to src/components/TaskList.tsx following our existing component patterns.
Add a new task completion feature to src/components/TaskList.tsx following our existing component patterns.
Include unit tests in tests/components/ and update the documentation in docs/features/.
The component should use our shared styling from src/styles/components.
```
Expand Down
16 changes: 16 additions & 0 deletions frontend/__tests__/components/chat/chat-input.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,22 @@ describe("ChatInput", () => {
expect(onSubmitMock).not.toHaveBeenCalled();
});

it("should not call onSubmit when the message is only whitespace", async () => {
const user = userEvent.setup();
render(<ChatInput onSubmit={onSubmitMock} />);
const textarea = screen.getByRole("textbox");

await user.type(textarea, " ");
await user.keyboard("{Enter}");

expect(onSubmitMock).not.toHaveBeenCalled();

await user.type(textarea, " \t\n");
await user.keyboard("{Enter}");

expect(onSubmitMock).not.toHaveBeenCalled();
});

it("should disable submit", async () => {
const user = userEvent.setup();
render(<ChatInput disabled onSubmit={onSubmitMock} />);
Expand Down
45 changes: 45 additions & 0 deletions frontend/__tests__/components/jupyter/jupyter.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { render, screen } from "@testing-library/react";
import { Provider } from "react-redux";
import { configureStore } from "@reduxjs/toolkit";
import { JupyterEditor } from "#/components/features/jupyter/jupyter";
import { jupyterReducer } from "#/state/jupyter-slice";
import { vi, describe, it, expect } from "vitest";

describe("JupyterEditor", () => {
const mockStore = configureStore({
reducer: {
fileState: () => ({}),
initalQuery: () => ({}),
browser: () => ({}),
chat: () => ({}),
code: () => ({}),
cmd: () => ({}),
agent: () => ({}),
jupyter: jupyterReducer,
securityAnalyzer: () => ({}),
status: () => ({}),
},
preloadedState: {
jupyter: {
cells: Array(20).fill({
content: "Test cell content",
type: "input",
output: "Test output",
}),
},
},
});

it("should have a scrollable container", () => {
render(
<Provider store={mockStore}>
<div style={{ height: "100vh" }}>
<JupyterEditor maxWidth={800} />
</div>
</Provider>
);

const container = screen.getByTestId("jupyter-container");
expect(container).toHaveClass("flex-1 overflow-y-auto");
});
});
2 changes: 1 addition & 1 deletion frontend/src/components/features/chat/chat-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export function ChatInput({

const handleSubmitMessage = () => {
const message = value || textareaRef.current?.value || "";
if (message) {
if (message.trim()) {
onSubmit(message);
onChange?.("");
if (textareaRef.current) {
Expand Down
7 changes: 4 additions & 3 deletions frontend/src/components/features/jupyter/jupyter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,17 @@ interface JupyterEditorProps {
}

export function JupyterEditor({ maxWidth }: JupyterEditorProps) {
const { cells } = useSelector((state: RootState) => state.jupyter);
const cells = useSelector((state: RootState) => state.jupyter?.cells ?? []);
const jupyterRef = React.useRef<HTMLDivElement>(null);

const { hitBottom, scrollDomToBottom, onChatBodyScroll } =
useScrollToBottom(jupyterRef);

return (
<div className="flex-1" style={{ maxWidth }}>
<div className="flex-1 h-full flex flex-col" style={{ maxWidth }}>
<div
className="overflow-y-auto h-full"
data-testid="jupyter-container"
className="flex-1 overflow-y-auto"
ref={jupyterRef}
onScroll={(e) => onChatBodyScroll(e.currentTarget)}
>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/routes/_oh.app.jupyter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function Jupyter() {
}, []);

return (
<div ref={parentRef}>
<div ref={parentRef} className="h-full">
<JupyterEditor maxWidth={parentWidth} />
</div>
);
Expand Down
9 changes: 5 additions & 4 deletions frontend/src/state/jupyter-slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ export type Cell = {

const initialCells: Cell[] = [];

export const cellSlice = createSlice({
name: "cell",
export const jupyterSlice = createSlice({
name: "jupyter",
initialState: {
cells: initialCells,
},
Expand All @@ -26,6 +26,7 @@ export const cellSlice = createSlice({
});

export const { appendJupyterInput, appendJupyterOutput, clearJupyter } =
cellSlice.actions;
jupyterSlice.actions;

export default cellSlice.reducer;
export const jupyterReducer = jupyterSlice.reducer;
export default jupyterReducer;
2 changes: 1 addition & 1 deletion frontend/src/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import codeReducer from "./state/code-slice";
import fileStateReducer from "./state/file-state-slice";
import initialQueryReducer from "./state/initial-query-slice";
import commandReducer from "./state/command-slice";
import jupyterReducer from "./state/jupyter-slice";
import { jupyterReducer } from "./state/jupyter-slice";
import securityAnalyzerReducer from "./state/security-analyzer-slice";
import statusReducer from "./state/status-slice";

Expand Down
4 changes: 3 additions & 1 deletion openhands/agenthub/codeact_agent/codeact_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,9 @@ def get_action_message(

# Add the LLM message (assistant) that initiated the tool calls
# (overwrites any previous message with the same response_id)
logger.debug(f'Tool calls type: {type(assistant_msg.tool_calls)}, value: {assistant_msg.tool_calls}')
logger.debug(
f'Tool calls type: {type(assistant_msg.tool_calls)}, value: {assistant_msg.tool_calls}'
)
pending_tool_call_action_messages[llm_response.id] = Message(
role=assistant_msg.role,
# tool call content SHOULD BE a string
Expand Down
2 changes: 0 additions & 2 deletions openhands/core/schema/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
from openhands.core.schema.action import ActionType
from openhands.core.schema.agent import AgentState
from openhands.core.schema.config import ConfigType
from openhands.core.schema.observation import ObservationType

__all__ = [
'ActionType',
'ObservationType',
'ConfigType',
'AgentState',
]
49 changes: 0 additions & 49 deletions openhands/core/schema/config.py

This file was deleted.

2 changes: 1 addition & 1 deletion openhands/runtime/impl/remote/remote_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def _check_existing_runtime(self) -> bool:
'GET',
f'{self.config.sandbox.remote_runtime_api_url}/sessions/{self.sid}',
is_retry=False,
timeout=5,
timeout=30,
) as response:
data = response.json()
status = data.get('status')
Expand Down
Loading

0 comments on commit 206f37a

Please sign in to comment.