Skip to content

Commit

Permalink
Merge branch 'main' into kevin
Browse files Browse the repository at this point in the history
  • Loading branch information
SmartManoj committed Dec 11, 2024
2 parents 1ff8280 + 5fa1851 commit b6b3286
Show file tree
Hide file tree
Showing 23 changed files with 359 additions and 56 deletions.
2 changes: 1 addition & 1 deletion .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ updates:
- "chromadb"
browsergym:
patterns:
- "browsergym"
- "browsergym*"
security-all:
applies-to: "security-updates"
patterns:
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/openhands-resolver.yml
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,8 @@ jobs:
if [ "${{ steps.check_result.outputs.RESOLUTION_SUCCESS }}" == "true" ]; then
cd /tmp && python -m openhands.resolver.send_pull_request \
--issue-number ${{ env.ISSUE_NUMBER }} \
--pr-type draft | tee pr_result.txt && \
--pr-type draft \
--reviewer ${{ github.actor }} | tee pr_result.txt && \
grep "draft created" pr_result.txt | sed 's/.*\///g' > pr_number.txt
else
cd /tmp && python -m openhands.resolver.send_pull_request \
Expand Down
73 changes: 69 additions & 4 deletions docs/modules/usage/how-to/gui-mode.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,75 @@ OpenHands provides a user-friendly Graphical User Interface (GUI) mode for inter

OpenHands automatically exports a `GITHUB_TOKEN` to the shell environment if it is available. This can happen in two ways:

1. Locally (OSS): The user directly inputs their GitHub token.
2. Online (SaaS): The token is obtained through GitHub OAuth authentication.

When you reach the `/app` route, the app checks if a token is present. If it finds one, it sets it in the environment for the agent to use.
1. **Locally (OSS)**: The user directly inputs their GitHub token
2. **Online (SaaS)**: The token is obtained through GitHub OAuth authentication

#### Setting Up a Local GitHub Token

1. **Generate a Personal Access Token (PAT)**:
- Go to GitHub Settings > Developer Settings > Personal Access Tokens > Tokens (classic)
- Click "Generate new token (classic)"
- Required scopes:
- `repo` (Full control of private repositories)
- `workflow` (Update GitHub Action workflows)
- `read:org` (Read organization data)

2. **Enter Token in OpenHands**:
- Click the Settings button (gear icon) in the top right
- Navigate to the "GitHub" section
- Paste your token in the "GitHub Token" field
- Click "Save" to apply the changes

#### Organizational Token Policies

If you're working with organizational repositories, additional setup may be required:

1. **Check Organization Requirements**:
- Organization admins may enforce specific token policies
- Some organizations require tokens to be created with SSO enabled
- Review your organization's [token policy settings](https://docs.github.com/en/organizations/managing-programmatic-access-to-your-organization/setting-a-personal-access-token-policy-for-your-organization)

2. **Verify Organization Access**:
- Go to your token settings on GitHub
- Look for the organization under "Organization access"
- If required, click "Enable SSO" next to your organization
- Complete the SSO authorization process

#### OAuth Authentication (Online Mode)

When using OpenHands in online mode, the GitHub OAuth flow:

1. Requests the following permissions:
- Repository access (read/write)
- Workflow management
- Organization read access

2. Authentication steps:
- Click "Sign in with GitHub" when prompted
- Review the requested permissions
- Authorize OpenHands to access your GitHub account
- If using an organization, authorize organization access if prompted

#### Troubleshooting

Common issues and solutions:

1. **Token Not Recognized**:
- Ensure the token is properly saved in settings
- Check that the token hasn't expired
- Verify the token has the required scopes
- Try regenerating the token

2. **Organization Access Denied**:
- Check if SSO is required but not enabled
- Verify organization membership
- Contact organization admin if token policies are blocking access

3. **Verifying Token Works**:
- The app will show a green checkmark if the token is valid
- Try accessing a repository to confirm permissions
- Check the browser console for any error messages
- Use the "Test Connection" button in settings if available

### Advanced Settings

Expand Down
8 changes: 4 additions & 4 deletions docs/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-icons": "^5.4.0",
"react-use": "^17.5.1"
"react-use": "^17.6.0"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "^3.5.1",
Expand Down
104 changes: 104 additions & 0 deletions evaluation/benchmarks/swe_bench/scripts/eval/verify_costs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import argparse

import pandas as pd

from openhands.core.logger import openhands_logger as logger


def verify_instance_costs(row: pd.Series) -> float:
"""
Verifies that the accumulated_cost matches the sum of individual costs in metrics.
Also checks for duplicate consecutive costs which might indicate buggy counting.
If the consecutive costs are identical, the file is affected by this bug:
https://github.com/All-Hands-AI/OpenHands/issues/5383
Args:
row: DataFrame row containing instance data with metrics
Returns:
float: The verified total cost for this instance (corrected if needed)
"""
try:
metrics = row.get('metrics')
if not metrics:
logger.warning(f"Instance {row['instance_id']}: No metrics found")
return 0.0

accumulated = metrics.get('accumulated_cost')
costs = metrics.get('costs', [])

if accumulated is None:
logger.warning(
f"Instance {row['instance_id']}: No accumulated_cost in metrics"
)
return 0.0

# Check for duplicate consecutive costs and systematic even-odd pairs
has_duplicate = False
all_pairs_match = True

# Check each even-odd pair (0-1, 2-3, etc.)
for i in range(0, len(costs) - 1, 2):
if abs(costs[i]['cost'] - costs[i + 1]['cost']) < 1e-6:
has_duplicate = True
logger.debug(
f"Instance {row['instance_id']}: Possible buggy double-counting detected! "
f"Steps {i} and {i+1} have identical costs: {costs[i]['cost']:.2f}"
)
else:
all_pairs_match = False
break

# Calculate total cost, accounting for buggy double counting if detected
if len(costs) >= 2 and has_duplicate and all_pairs_match:
paired_steps_cost = sum(
cost_entry['cost']
for cost_entry in costs[: -1 if len(costs) % 2 else None]
)
real_paired_cost = paired_steps_cost / 2

unpaired_cost = costs[-1]['cost'] if len(costs) % 2 else 0
total_cost = real_paired_cost + unpaired_cost

else:
total_cost = sum(cost_entry['cost'] for cost_entry in costs)

if not abs(total_cost - accumulated) < 1e-6:
logger.warning(
f"Instance {row['instance_id']}: Cost mismatch: "
f"accumulated: {accumulated:.2f}, sum of costs: {total_cost:.2f}, "
)

return total_cost

except Exception as e:
logger.error(
f"Error verifying costs for instance {row.get('instance_id', 'UNKNOWN')}: {e}"
)
return 0.0


def main():
parser = argparse.ArgumentParser(
description='Verify costs in SWE-bench output file'
)
parser.add_argument(
'input_filepath', type=str, help='Path to the output.jsonl file'
)
args = parser.parse_args()

try:
# Load and verify the JSONL file
df = pd.read_json(args.input_filepath, lines=True)
logger.info(f'Loaded {len(df)} instances from {args.input_filepath}')

# Verify costs for each instance and sum up total
total_cost = df.apply(verify_instance_costs, axis=1).sum()
logger.info(f'Total verified cost across all instances: ${total_cost:.2f}')

except Exception as e:
logger.error(f'Failed to process file: {e}')
raise


if __name__ == '__main__':
main()
2 changes: 2 additions & 0 deletions frontend/__tests__/components/browser.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ describe("Browser", () => {
browser: {
url: "https://example.com",
screenshotSrc: "",
updateCount: 0,
},
},
});
Expand All @@ -26,6 +27,7 @@ describe("Browser", () => {
url: "https://example.com",
screenshotSrc:
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mN0uGvyHwAFCAJS091fQwAAAABJRU5ErkJggg==",
updateCount: 0,
},
},
});
Expand Down
9 changes: 9 additions & 0 deletions frontend/src/components/features/file-explorer/tree-node.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React from "react";
import { useSelector } from "react-redux";

import { useFiles } from "#/context/files";
import { cn } from "#/utils/utils";
import { useListFiles } from "#/hooks/query/use-list-files";
import { useListFile } from "#/hooks/query/use-list-file";
import { Filename } from "./filename";
import { RootState } from "#/store";

interface TreeNodeProps {
path: string;
Expand All @@ -20,6 +22,7 @@ function TreeNode({ path, defaultOpen = false }: TreeNodeProps) {
selectedPath,
} = useFiles();
const [isOpen, setIsOpen] = React.useState(defaultOpen);
const { curAgentState } = useSelector((state: RootState) => state.agent);

const isDirectory = path.endsWith("/");

Expand All @@ -39,6 +42,12 @@ function TreeNode({ path, defaultOpen = false }: TreeNodeProps) {
}
}, [fileContent, path]);

React.useEffect(() => {
if (selectedPath === path && !isDirectory) {
refetch();
}
}, [curAgentState, selectedPath, path, isDirectory]);

const fileParts = path.split("/");
const filename =
fileParts[fileParts.length - 1] || fileParts[fileParts.length - 2];
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/features/sidebar/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@ export function Sidebar() {

return (
<>
<aside className="px-1 flex flex-col gap-1">
<aside className="h-[40px] md:h-auto px-1 flex flex-row md:flex-col gap-1">
<div className="w-[34px] h-[34px] flex items-center justify-center">
{user.isLoading && <LoadingSpinner size="small" />}
{!user.isLoading && <AllHandsLogoButton onClick={handleClickLogo} />}
</div>

<nav className="py-[18px] flex flex-col items-center gap-[18px]">
<nav className="md:py-[18px] flex flex-row md:flex-col items-center gap-[18px]">
<UserActions
user={user.data ? { avatar_url: user.data.avatar_url } : undefined}
onLogout={logout}
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/layout/container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { NavTab } from "./nav-tab";
interface ContainerProps {
label?: string;
labels?: {
label: string;
label: string | React.ReactNode;
to: string;
icon?: React.ReactNode;
isBeta?: boolean;
Expand Down Expand Up @@ -65,7 +65,7 @@ export function Container({
)}
</div>
)}
<div className="overflow-auto h-full rounded-b-xl">{children}</div>
<div className="overflow-hidden h-full rounded-b-xl">{children}</div>
</div>
);
}
7 changes: 7 additions & 0 deletions frontend/src/components/layout/count-badge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export function CountBadge({ count }: { count: number }) {
return (
<span className="text-[11px] leading-5 text-root-primary bg-neutral-400 px-1 rounded-xl">
{count}
</span>
);
}
2 changes: 1 addition & 1 deletion frontend/src/components/layout/nav-tab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { BetaBadge } from "./beta-badge";

interface NavTabProps {
to: string;
label: string;
label: string | React.ReactNode;
icon: React.ReactNode;
isBeta?: boolean;
}
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/i18n/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -2023,6 +2023,9 @@
"ACTION_MESSAGE$WRITE": {
"en": "Writing to a file"
},
"ACTION_MESSAGE$BROWSE": {
"en": "Browsing the web"
},
"OBSERVATION_MESSAGE$RUN": {
"en": "Ran a bash command"
},
Expand All @@ -2035,6 +2038,9 @@
"OBSERVATION_MESSAGE$WRITE": {
"en": "Wrote to a file"
},
"OBSERVATION_MESSAGE$BROWSE": {
"en": "Browsing completed"
},
"EXPANDABLE_MESSAGE$SHOW_DETAILS": {
"en": "Show details"
},
Expand Down
Loading

0 comments on commit b6b3286

Please sign in to comment.