mirror of
https://github.com/Sea-Haven-Industries/open-swe.git
synced 2026-09-30 10:23:14 +00:00
fix: bug with checking out the branch during followups (#679)
* fix: bug with checking out the branch during followups * cr * cr * cr * cr
This commit is contained in:
parent
0591a907c7
commit
df182b676b
13 changed files with 139 additions and 118 deletions
|
|
@ -25,7 +25,7 @@ export async function submitFeedback({
|
|||
plannerFeedback: string;
|
||||
plannerThreadId: string;
|
||||
setLogs: (updater: (prev: string[]) => string[]) => void; // eslint-disable-line no-unused-vars
|
||||
setPlannerFeedback: () => void; // eslint-disable-line no-unused-vars
|
||||
setPlannerFeedback: () => void;
|
||||
setStreamingPhase: (phase: "streaming" | "awaitingFeedback" | "done") => void; // eslint-disable-line no-unused-vars
|
||||
}) {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ Before starting, ensure you have the following installed:
|
|||
GITHUB_APP_REDIRECT_URI="http://localhost:3000/api/auth/github/callback"
|
||||
|
||||
# GitHub App details (will be filled after creating GitHub App)
|
||||
GITHUB_APP_NAME="open-swe-dev"
|
||||
GITHUB_APP_NAME="open-swe-dev" # this must match the name of your GitHub app, excluding spaces
|
||||
GITHUB_APP_ID=""
|
||||
GITHUB_APP_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----
|
||||
...add your private key here...
|
||||
|
|
@ -105,7 +105,7 @@ Before starting, ensure you have the following installed:
|
|||
FIRECRAWL_API_KEY="" # For URL content extraction
|
||||
|
||||
# GitHub App settings (same as web app)
|
||||
GITHUB_APP_NAME="open-swe-dev"
|
||||
GITHUB_APP_NAME="open-swe-dev" # this must match the name of your GitHub app, excluding spaces
|
||||
GITHUB_APP_ID=""
|
||||
GITHUB_APP_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----
|
||||
...add your private key here...
|
||||
|
|
|
|||
|
|
@ -25,9 +25,7 @@ FIRECRAWL_API_KEY=""
|
|||
|
||||
|
||||
# ------------------Github App Secrets-----------------
|
||||
# Used for setting the git user name & email for commits.
|
||||
# Can modify to whatever string you want.
|
||||
GITHUB_APP_NAME="open-swe-dev"
|
||||
GITHUB_APP_NAME="open-swe-dev" # this must match the name of your GitHub app, excluding spaces
|
||||
GITHUB_APP_ID=""
|
||||
# App secret key. Should be multi-line.
|
||||
GITHUB_APP_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----
|
||||
|
|
@ -54,5 +52,6 @@ SECRETS_ENCRYPTION_KEY=""
|
|||
# See the documentation for how to set this up: docs.langchain.com/labs/swe/setup/ci#skip-ci-until-last-commit
|
||||
SKIP_CI_UNTIL_LAST_COMMIT="true"
|
||||
|
||||
OPEN_SWE_LOCAL_MODE=true
|
||||
OPEN_SWE_LOCAL_PROJECT_PATH=""
|
||||
# For the CLI to work, you need to set these variables.
|
||||
# OPEN_SWE_LOCAL_MODE=false
|
||||
# OPEN_SWE_LOCAL_PROJECT_PATH=""
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
"postinstall": "turbo build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@daytonaio/sdk": "^0.25.4",
|
||||
"@daytonaio/sdk": "^0.25.5",
|
||||
"@langchain/anthropic": "^0.3.26",
|
||||
"@langchain/community": "^0.3.47",
|
||||
"@langchain/core": "^0.3.65",
|
||||
|
|
|
|||
|
|
@ -286,10 +286,13 @@ export async function initializeSandbox(
|
|||
stateBranchName: branchName,
|
||||
});
|
||||
},
|
||||
{ retries: 3, delay: 0 },
|
||||
{ retries: 0, delay: 0 },
|
||||
);
|
||||
|
||||
if (cloneRepoRes instanceof Error) {
|
||||
if (
|
||||
cloneRepoRes instanceof Error &&
|
||||
!cloneRepoRes.message.includes("repository already exists")
|
||||
) {
|
||||
emitStepEvent(
|
||||
baseCloneRepoAction,
|
||||
"error",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { Octokit } from "@octokit/rest";
|
||||
import { createLogger, LogLevel } from "../logger.js";
|
||||
import {
|
||||
GitHubBranch,
|
||||
GitHubIssue,
|
||||
GitHubIssueComment,
|
||||
GitHubPullRequest,
|
||||
|
|
@ -555,3 +556,35 @@ export async function updateIssueComment({
|
|||
numRetries,
|
||||
);
|
||||
}
|
||||
|
||||
export async function getBranch({
|
||||
owner,
|
||||
repo,
|
||||
branchName,
|
||||
githubInstallationToken,
|
||||
}: {
|
||||
owner: string;
|
||||
repo: string;
|
||||
branchName: string;
|
||||
githubInstallationToken: string;
|
||||
}): Promise<GitHubBranch | null> {
|
||||
return withGitHubRetry(
|
||||
async (token: string) => {
|
||||
const octokit = new Octokit({
|
||||
auth: token,
|
||||
});
|
||||
|
||||
const { data: branch } = await octokit.repos.getBranch({
|
||||
owner,
|
||||
repo,
|
||||
branch: branchName,
|
||||
});
|
||||
|
||||
return branch;
|
||||
},
|
||||
githubInstallationToken,
|
||||
"Failed to get branch",
|
||||
undefined,
|
||||
1,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import {
|
|||
getActiveTask,
|
||||
getPullRequestNumberFromActiveTask,
|
||||
} from "@open-swe/shared/open-swe/tasks";
|
||||
import { createPullRequest } from "./api.js";
|
||||
import { createPullRequest, getBranch } from "./api.js";
|
||||
import { addTaskPlanToIssue } from "./issue-task.js";
|
||||
import { DEFAULT_EXCLUDED_PATTERNS } from "./constants.js";
|
||||
import { escapeRegExp } from "../string-utils.js";
|
||||
|
|
@ -523,11 +523,32 @@ async function performClone(
|
|||
baseCommit: targetRepository.baseCommit,
|
||||
});
|
||||
|
||||
if (!branchName && !targetRepository.baseCommit) {
|
||||
throw new Error(
|
||||
"Can not create new branch or checkout existing branch without branch name",
|
||||
);
|
||||
}
|
||||
|
||||
const branchExists = branchName
|
||||
? !!(await getBranch({
|
||||
owner: targetRepository.owner,
|
||||
repo: targetRepository.repo,
|
||||
branchName,
|
||||
githubInstallationToken,
|
||||
}))
|
||||
: false;
|
||||
|
||||
if (branchExists) {
|
||||
logger.info("Branch already exists on remote. Cloning existing branch.", {
|
||||
branch: branchName,
|
||||
});
|
||||
}
|
||||
|
||||
await sandbox.git.clone(
|
||||
cloneUrl,
|
||||
absoluteRepoDir,
|
||||
targetRepository.branch,
|
||||
targetRepository.baseCommit,
|
||||
branchExists ? branchName : targetRepository.branch,
|
||||
branchExists ? undefined : targetRepository.baseCommit,
|
||||
"git",
|
||||
githubInstallationToken,
|
||||
);
|
||||
|
|
@ -543,45 +564,51 @@ async function performClone(
|
|||
}
|
||||
|
||||
if (!branchName) {
|
||||
throw new Error(
|
||||
"Can not create new branch or checkout existing branch without branch name",
|
||||
);
|
||||
throw new Error("Branch name is required");
|
||||
}
|
||||
|
||||
if (branchExists) {
|
||||
return branchName;
|
||||
}
|
||||
|
||||
try {
|
||||
logger.info("Creating branch", {
|
||||
branch: branchName,
|
||||
});
|
||||
|
||||
await sandbox.git.createBranch(absoluteRepoDir, branchName);
|
||||
|
||||
logger.info("Created branch", {
|
||||
branch: branchName,
|
||||
});
|
||||
|
||||
// push an empty commit so that the branch exists in the remote
|
||||
await sandbox.git.push(absoluteRepoDir, "git", githubInstallationToken);
|
||||
logger.info("Pushed empty commit to remote", {
|
||||
branch: branchName,
|
||||
});
|
||||
|
||||
return branchName;
|
||||
} catch {
|
||||
logger.info("Failed to create branch, checking out branch", {
|
||||
} catch (error) {
|
||||
logger.error("Failed to create branch, checking out branch", {
|
||||
branch: branchName,
|
||||
error:
|
||||
error instanceof Error
|
||||
? { name: error.name, message: error.message }
|
||||
: String(error),
|
||||
});
|
||||
}
|
||||
|
||||
await sandbox.git.checkoutBranch(absoluteRepoDir, branchName);
|
||||
logger.info("Checked out branch", {
|
||||
branch: branchName,
|
||||
});
|
||||
|
||||
const setUpstreamBranchRes = await sandbox.process.executeCommand(
|
||||
`git branch --set-upstream-to=origin/${branchName}`,
|
||||
absoluteRepoDir,
|
||||
);
|
||||
if (setUpstreamBranchRes.exitCode !== 0) {
|
||||
logger.error("Failed to set upstream branch", {
|
||||
setUpstreamBranchRes,
|
||||
try {
|
||||
// push an empty commit so that the branch exists in the remote
|
||||
logger.info("Pushing empty commit to remote", {
|
||||
branch: branchName,
|
||||
});
|
||||
await sandbox.git.push(absoluteRepoDir, "git", githubInstallationToken);
|
||||
|
||||
logger.info("Pushed empty commit to remote", {
|
||||
branch: branchName,
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error("Failed to push an empty commit to branch", {
|
||||
branch: branchName,
|
||||
error:
|
||||
error instanceof Error
|
||||
? { name: error.name, message: error.message }
|
||||
: String(error),
|
||||
});
|
||||
} else {
|
||||
logger.info("Set upstream branch");
|
||||
}
|
||||
|
||||
return branchName;
|
||||
|
|
|
|||
|
|
@ -14,3 +14,6 @@ export type GitHubPullRequestUpdate =
|
|||
|
||||
export type GitHubPullRequestList =
|
||||
RestEndpointMethodTypes["pulls"]["list"]["response"]["data"];
|
||||
|
||||
export type GitHubBranch =
|
||||
RestEndpointMethodTypes["repos"]["getBranch"]["response"]["data"];
|
||||
|
|
|
|||
|
|
@ -7,9 +7,7 @@ GITHUB_APP_CLIENT_SECRET=""
|
|||
# your GitHub app settings.
|
||||
GITHUB_APP_REDIRECT_URI="http://localhost:3000/api/auth/github/callback"
|
||||
|
||||
# Used for setting the git user name & email for commits.
|
||||
# Can modify to whatever string you want.
|
||||
GITHUB_APP_NAME="open-swe-dev"
|
||||
GITHUB_APP_NAME="open-swe-dev" # this must match the name of your GitHub app, excluding spaces
|
||||
GITHUB_APP_ID=""
|
||||
# App secret key. Should be multi-line.
|
||||
GITHUB_APP_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----
|
||||
|
|
|
|||
|
|
@ -208,45 +208,6 @@ export function ConfigManager() {
|
|||
updateConfig(DEFAULT_CONFIG_KEY, config.label, value);
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
{(() => {
|
||||
const currentValue =
|
||||
configs[DEFAULT_CONFIG_KEY]?.[config.label];
|
||||
const defaultValue = defaultConfig.find(
|
||||
(c) => c.label === config.label,
|
||||
)?.default;
|
||||
const isModified =
|
||||
currentValue !== undefined &&
|
||||
currentValue !== defaultValue;
|
||||
|
||||
return (
|
||||
isModified && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={() => {
|
||||
// Remove the config value to revert to default
|
||||
// This effectively "unsets" the user's custom value
|
||||
const existingConfig =
|
||||
getConfig(DEFAULT_CONFIG_KEY) || {};
|
||||
const {
|
||||
[config.label]: _,
|
||||
...remainingConfig
|
||||
} = existingConfig;
|
||||
updateConfig(
|
||||
DEFAULT_CONFIG_KEY,
|
||||
"",
|
||||
remainingConfig,
|
||||
);
|
||||
}}
|
||||
>
|
||||
Reset to Default
|
||||
</Button>
|
||||
)
|
||||
);
|
||||
})()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,10 +1,16 @@
|
|||
import { MessageContent } from "@langchain/core/messages";
|
||||
|
||||
export function getMessageContentString(content: MessageContent): string {
|
||||
if (typeof content === "string") return content;
|
||||
try {
|
||||
if (typeof content === "string") return content;
|
||||
|
||||
return content
|
||||
.filter((c): c is { type: "text"; text: string } => c.type === "text")
|
||||
.map((c) => c.text)
|
||||
.join(" ");
|
||||
return content
|
||||
.filter((c): c is { type: "text"; text: string } => c.type === "text")
|
||||
.map((c) => c.text)
|
||||
.join(" ");
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error("Failed to get message content string", error);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
export const MODEL_OPTIONS = [
|
||||
{
|
||||
label: "Claude Sonnet 4 (Extended Thinking)",
|
||||
value: "anthropic:extended-thinking:claude-sonnet-4-0",
|
||||
},
|
||||
{
|
||||
label: "Claude Opus 4 (Extended Thinking)",
|
||||
value: "anthropic:extended-thinking:claude-opus-4-0",
|
||||
},
|
||||
// TODO: Test these then re-enable
|
||||
// {
|
||||
// label: "Claude Sonnet 4 (Extended Thinking)",
|
||||
// value: "anthropic:extended-thinking:claude-sonnet-4-0",
|
||||
// },
|
||||
// {
|
||||
// label: "Claude Opus 4 (Extended Thinking)",
|
||||
// value: "anthropic:extended-thinking:claude-opus-4-0",
|
||||
// },
|
||||
{
|
||||
label: "Claude Sonnet 4",
|
||||
value: "anthropic:claude-sonnet-4-0",
|
||||
|
|
|
|||
34
yarn.lock
34
yarn.lock
|
|
@ -1282,33 +1282,32 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@daytonaio/api-client@npm:0.25.4":
|
||||
version: 0.25.4
|
||||
resolution: "@daytonaio/api-client@npm:0.25.4"
|
||||
"@daytonaio/api-client@npm:0.25.5":
|
||||
version: 0.25.5
|
||||
resolution: "@daytonaio/api-client@npm:0.25.5"
|
||||
dependencies:
|
||||
axios: ^1.6.1
|
||||
checksum: c3ff09da2af437620bada5c6161e52104ec32a2ef0f3a890d4da5458015e78e9de7ee28954e423477dc5fd7a8a07f58e5fd1fc919d9f382e86b6ad2da8b421c6
|
||||
checksum: 208fd54526f9f3b40ef8ca137e6f6d68ac4cef0e63b51cda1cb7a91ffa23dc3875a49bfc4eda271f0f1cb86ba21e33234b68b5a51591882cc13508ccba29f8d2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@daytonaio/sdk@npm:^0.25.4":
|
||||
version: 0.25.4
|
||||
resolution: "@daytonaio/sdk@npm:0.25.4"
|
||||
"@daytonaio/sdk@npm:^0.25.5":
|
||||
version: 0.25.5
|
||||
resolution: "@daytonaio/sdk@npm:0.25.5"
|
||||
dependencies:
|
||||
"@aws-sdk/client-s3": ^3.787.0
|
||||
"@aws-sdk/lib-storage": ^3.798.0
|
||||
"@daytonaio/api-client": 0.25.4
|
||||
"@daytonaio/api-client": 0.25.5
|
||||
"@iarna/toml": ^2.2.5
|
||||
axios: ^1.6.1
|
||||
dotenv: ^17.0.1
|
||||
expand-tilde: ^2.0.2
|
||||
fast-glob: ^3.3.0
|
||||
form-data: ^4.0.0
|
||||
isomorphic-ws: 5.0.0
|
||||
form-data: ^4.0.4
|
||||
pathe: ^2.0.3
|
||||
shell-quote: ^1.8.2
|
||||
tar: ^6.2.0
|
||||
checksum: d3d6e35c8c27a69c4cd8e241b9e1e4ac2171136718dc0ec21bf20e63e0d027f29a37ab16909025f14f891428055c9493382d72fe368d8db391249f59b4f00e21
|
||||
checksum: 692edc134c56bb83037870a750b81792b5592fdc5cf13d9b2d6ecfd522866d433bfb9e8943a3d4caf169b1d69969048079b0e876354e83035840fed4173b0c37
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
|
@ -4093,7 +4092,7 @@ __metadata:
|
|||
version: 0.0.0-use.local
|
||||
resolution: "@open-swe/agent@workspace:apps/open-swe"
|
||||
dependencies:
|
||||
"@daytonaio/sdk": ^0.25.4
|
||||
"@daytonaio/sdk": ^0.25.5
|
||||
"@eslint/eslintrc": ^3.1.0
|
||||
"@eslint/js": ^9.19.0
|
||||
"@jest/globals": ^29.7.0
|
||||
|
|
@ -11348,7 +11347,7 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"form-data@npm:^4.0.0, form-data@npm:^4.0.4":
|
||||
"form-data@npm:^4.0.4":
|
||||
version: 4.0.4
|
||||
resolution: "form-data@npm:4.0.4"
|
||||
dependencies:
|
||||
|
|
@ -13103,15 +13102,6 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"isomorphic-ws@npm:5.0.0":
|
||||
version: 5.0.0
|
||||
resolution: "isomorphic-ws@npm:5.0.0"
|
||||
peerDependencies:
|
||||
ws: "*"
|
||||
checksum: e20eb2aee09ba96247465fda40c6d22c1153394c0144fa34fe6609f341af4c8c564f60ea3ba762335a7a9c306809349f9b863c8beedf2beea09b299834ad5398
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"istanbul-lib-coverage@npm:^3.0.0, istanbul-lib-coverage@npm:^3.2.0":
|
||||
version: 3.2.2
|
||||
resolution: "istanbul-lib-coverage@npm:3.2.2"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue