Commit graph

194 commits

Author SHA1 Message Date
Johannes du Plessis
d2b3cb01c0
fix: flag skipped CI tests in reviewer (#1428)
Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
2026-06-05 10:31:00 -07:00
Johannes du Plessis
6a9fd85295
fix: guard reviewer GraphQL against null repository (#1426)
GitHub returns repository: null when the token can't read the repo (SAML,
expired token, private/deleted). dict.get(k, {}) doesn't coalesce explicit
null, so fetch_pr_review_threads crashed with AttributeError and publish_review
could never post a review. Guard with isinstance checks and return collected
threads on null repository; sweep the same pattern in resolve_review_thread.

Co-authored-by: open-swe[bot] <215916821+open-swe[bot]@users.noreply.github.com>
2026-06-05 09:37:42 -07:00
Ramon Nogueira
bbe449244a
feat: make web threads readable by any org user (#1425)
* feat: make web threads viewable by any org user

Reads (get/stream) now allow any logged-in org user to view a thread
whose source is surfaced (dashboard/github/slack/linear/schedule),
instead of requiring ownership. Internal reviewer/analyzer threads stay
hidden via the same source filter. Writes (send/cancel/delete) remain
owner-only.

Adds GET /threads?all=true to list every surfaced thread; the default
list stays per-user.

* feat: make all web threads readable by any org user

Drop the per-thread source/owner gate on reads: any logged-in org user
can now view and stream any thread, including reviewer/analyzer threads.
GET /threads?all=true returns every thread regardless of source. Writes
(send/cancel/delete) stay owner-only. All routes remain behind the
session + org-login gate.
2026-06-05 08:28:08 -07:00
Johannes du Plessis
3a91fbfabc
fix: revert co-author email to open-swe user noreply (#1424)
The bot's numeric noreply (215916821+open-swe[bot]@users.noreply.github.com)
introduced in ae946d1a doesn't resolve to a GitHub account Vercel accepts,
breaking preview deploys on PRs in langchainplus. Revert OPEN_SWE_BOT_EMAIL
to open-swe@users.noreply.github.com.

Co-authored-by: open-swe[bot] <215916821+open-swe[bot]@users.noreply.github.com>
2026-06-04 19:28:16 -07:00
Johannes du Plessis
6895ddcedc
feat: add scheduled web agents (#1422)
* feat: add scheduled web agents

Co-authored-by: open-swe[bot] <215916821+open-swe[bot]@users.noreply.github.com>

* fix: secure scheduled agent repositories

Co-authored-by: open-swe[bot] <215916821+open-swe[bot]@users.noreply.github.com>

* feat: rebuild scheduled agents as Automations tab

Scrap the inline ScheduledAgentsPanel and replace it with a dedicated
Automations tab: sidebar nav entry, list view with stat cards + empty
state, and a full editor (name, Active toggle, repo, scheduled trigger
picker, agent instructions + model).

* fix: clear collapsed-sidebar button on mobile in Automations

* fix: allow clearing automation repo on update

---------

Co-authored-by: open-swe[bot] <215916821+open-swe[bot]@users.noreply.github.com>
2026-06-05 02:20:24 +00:00
Johannes du Plessis
f1baceb8ab
feat: add Gemini 3.5 Flash provider (#1420) 2026-06-04 17:38:54 -07:00
Johannes du Plessis
a511add856
feat: add agent usage leaderboard (#1418)
* feat: add agent usage leaderboard

Co-authored-by: open-swe[bot] <215916821+open-swe[bot]@users.noreply.github.com>

* fix: bound leaderboard refresh and hide emails

Co-authored-by: open-swe[bot] <215916821+open-swe[bot]@users.noreply.github.com>

---------

Co-authored-by: open-swe[bot] <215916821+open-swe[bot]@users.noreply.github.com>
2026-06-04 23:33:31 +00:00
Johannes du Plessis
a26d5d32cb
feat: Add Fireworks model provider (#1415)
* feat: add Fireworks model provider with accurate reasoning levels

Adds Kimi K2.6, DeepSeek V4 Pro, Nemotron 3 Ultra, GLM 5.1 via fireworks: provider, mapping per-model reasoning_effort. Surfaces each model's real effort range (incl. openai none, deepseek xhigh/max).

* fix: drop serverless-unsupported Nemotron 3 Ultra, document FIREWORKS_API_KEY

---------

Co-authored-by: open-swe[bot] <215916821+open-swe[bot]@users.noreply.github.com>
2026-06-04 21:59:47 +00:00
Johannes du Plessis
a75e9b027b
fix: stabilize agent selector defaults (#1414)
* fix: stabilize agent defaults and repo selector

Co-authored-by: open-swe[bot] <215916821+open-swe[bot]@users.noreply.github.com>

* fix: align default repo selector styling, restore text fallback

Match the repo selector to sibling settings controls (h-7, bg-input/20,
text-xs). Fall back to a text input when the repo list is empty so a
default repo can still be entered.

* fix: make repo selector dropdown more compact

---------

Co-authored-by: open-swe[bot] <215916821+open-swe[bot]@users.noreply.github.com>
2026-06-04 21:06:25 +00:00
Johannes du Plessis
8b18e7e95d
fix: Reduce graph load and dashboard repo failures (#1412)
* fix: reduce graph load and dashboard repo failures

* fix: surface repo listing timeouts
2026-06-04 13:54:06 -07:00
Johannes du Plessis
9df5883d1f
fix: retry transient LangSmith proxy config failures (#1413) 2026-06-04 13:51:57 -07:00
Johannes du Plessis
58f7b716da
fix: suppress blocked GitHub webhook warnings (#1411)
Demote expected GitHub allowlist rejections to debug so external app installations do not flood warning logs.
2026-06-04 20:23:29 +00:00
Johannes du Plessis
58e0f84470
fix: use Slack OIDC mappings for Slack thread ownership (#1410)
* fix: tag Slack threads with stored identity so they surface in web

process_slack_mention gated the run on mapped_login (resolved from the stable
Slack user id), but upsert_agent_thread_owner_metadata independently re-resolved
the GitHub login from the Slack profile email. When that email differs from the
user's mapping email (e.g. a personal vs work address), the lookup returned None,
so github_login was never stamped on the thread and the thread never surfaced in
the web Agents UI (which searches by github_login / triggering_user_email).

Resolve the GitHub user from the store via the Slack id, pass that login through
to the owner metadata, and use the mapping's stored work email (falling back to
the Slack profile email for unmapped users) for both the run config and the
thread tagging, so Slack-started threads reliably appear in web.

* fix: stamp github_login on Slack threads so they surface in web

process_slack_mention gated the run on mapped_login (resolved from the stable
Slack user id) but upsert_agent_thread_owner_metadata re-resolved the login from
the Slack profile email; when that email isn't the user's mapping email the
lookup returns None and github_login is never stamped, so the thread is invisible
in the web Agents UI (which searches by github_login / triggering_user_email).

Pass the already-resolved mapped_login through to the owner metadata. The
dashboard match keys on the stable GitHub login, so this is sufficient; the
triggering email stays the live Slack profile value.

* fix: preserve Slack email during account mapping

* fix: require Slack OIDC for email mappings

* chore: format Slack OIDC mapping cleanup
2026-06-04 19:58:30 +00:00
Johannes du Plessis
60426e8b10
fix: reviewer resolves GitHub App token at run start, not via cross-process cache (#1409)
Reviewer/push runs execute in a worker process, but the GitHub token was
cached by the webhook handler in the API server process — a different
process — so the worker's in-process cache was always cold. resolve_github_token
then failed (User not authenticated / Unknown source: github_push) and only the
app-token fallback kept reviews working, noisily.

The reviewer always acts as the GitHub App (open-swe[bot]), so resolve the
installation token directly at run start, scoped to the repo. This also bypasses
org SAML enforcement that blocks user OAuth tokens. Drop the now-dead
cross-process cache writes in the webhook reviewer-dispatch handlers, and stop
leave_failure_comment raising on the github_push source.
2026-06-04 12:11:23 -07:00
Johannes du Plessis
c1e46b938e
feat: add Slack Block Kit reply options (#1407)
* feat: add Slack Block Kit reply options

Co-authored-by: open-swe[bot] <215916821+open-swe[bot]@users.noreply.github.com>

* docs: document Slack interactivity setup

Co-authored-by: open-swe[bot] <215916821+open-swe[bot]@users.noreply.github.com>

---------

Co-authored-by: open-swe[bot] <215916821+open-swe[bot]@users.noreply.github.com>
2026-06-04 10:26:09 -07:00
Johannes du Plessis
5e9dcdb21d
fix: prioritize web replies after Slack handoff (#1406) 2026-06-04 10:01:10 -07:00
Brace Sproul
2070a770c2
fix: stop storing GitHub tokens in metadata (#1405)
* fix: stop storing GitHub tokens in metadata

Co-authored-by: open-swe[bot] <215916821+open-swe[bot]@users.noreply.github.com>

* fix: bound in-process GitHub token cache with 24h TTL + sweep

---------

Co-authored-by: open-swe[bot] <215916821+open-swe[bot]@users.noreply.github.com>
Co-authored-by: open-swe[bot] <johannes@langchain.dev>
2026-06-04 09:33:51 -07:00
Johannes du Plessis
ce24a47cdf
fix: auto-create local sandbox root dir (#1402)
create_local_sandbox now mkdir -p's the resolved root dir, so a custom
LOCAL_SANDBOX_ROOT_DIR (or a /tmp path cleared on reboot) no longer fails
sandbox work-dir resolution.
2026-06-03 23:47:08 +00:00
ericness
6b005cfb67
fix: include resolved repo in Linear prompt to prevent repo ambiguity (#1307)
The Linear webhook (`process_linear_issue` in `agent/webapp.py`) was the
only trigger whose user prompt did not surface the resolved repo to the
LLM:

- Slack:        `## Default Repository Hint` (line 947)
- GitHub issue: `## Repository: ...`         (`build_github_issue_prompt`, line 1443)
- GitHub PR:    `## Repository: ...`         (`build_github_pr_review_prompt`, line 1526)
- Linear:       (missing)

`configurable["repo"]` was still being set and consumed by
`commit_and_open_pr`, but the agent itself never saw it. For tasks
routed via Linear team/project mapping, the LLM had to guess which
repo to clone — frequently falling back to `langchain-ai/open-swe`
(via `SELF_AWARENESS_SECTION` in `agent/prompt.py`) or
`langchain-ai/langchainplus` (via `default_prompt.md`), silently
targeting the wrong repository.

This is a regression: commit 5e4c6bb8 on branch `yogesh/stop-auto-cloning`
("fix: include resolved repo in Linear prompt to prevent repo ambiguity",
2026-03-16) added this exact line, but it was dropped when that branch
was squash-merged as PR #1159 ("feat: stop auto-cloning and let agent
manage repo setup", 2039fe66, 2026-04-10). Subsequent refactors
(e215f1ef, f662ad65) preserved the gap.

Adding the line back mirrors the GitHub/Slack prompt builders and
matches the rationale of e215f1ef ("Linear team/project mapping handles
per-team routing"): routing is correct, the prompt just wasn't
propagating it.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Johannes du Plessis <johannes@langchain.dev>
2026-06-03 15:08:07 -07:00
Johannes du Plessis
27677c4949
feat(dashboard): render Slack/Linear replies as a card in chat (#1399)
Slack thread replies and Linear comments showed only the bare tool name in the dashboard chat. Map them to dedicated 'slack'/'linear' toolKinds and render the message body in a ReplyCard, so Open-in-Web shows what the agent actually posted.
2026-06-03 22:05:47 +00:00
Johannes du Plessis
dee78e7e84
fix: make repository optional when starting a dashboard run (#1397)
* fix: make repository optional when starting a dashboard run

The agent infers and clones the target repo from the task itself, so a
default repo is never actually required to run — but the dashboard 400'd
("no default repository configured") when a user had none set.

Treat repo as optional: _resolve_repo_config returns {} instead of
raising, repo metadata/config are only written when a repo is present,
and the "missing repository metadata" gate on follow-up messages is
dropped. UI hides the repo chip when absent.

* feat: add repo picker to the run prompt bar

Adds an optional, searchable repository selector next to the model picker
on the Agents home prompt bar (Cursor-style). It pre-fills the user's saved
default repo and can be cleared to "No repository" for a repo-less run.

Because the picker now resolves the default on the client, the create
endpoint honors the request value verbatim: _resolve_repo_config just parses
what's sent ({} when empty) instead of falling back to the saved default,
so an explicit "No repository" is respected.

* refactor: match Cursor layout for repo placement

Move the repo selector out of the prompt-box footer to a pill row above
the input (folder + caret, dropdown opens downward); the model picker
stays inside the box. In the thread view, show the thread title and repo
in a header at the top of the chat, with the follow-up input pinned to
the bottom as before.
2026-06-03 14:24:08 -07:00
Johannes du Plessis
8913926dba
fix: remove manual review trigger surfaces (#1396)
Open SWE Review now runs from automated PR triggers, so drop the old Slack/GitHub review keyword entrypoints and keep PR comments on the regular agent path.
2026-06-03 12:33:22 -07:00
Mukil Loganathan
f4b27c0fee
feat: add Slack Open in Web link (#1392)
* feat: add Slack Open in Web link

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>

* fix: skip web link for Slack reviewer runs

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>

* test: accept include_dashboard_link kwarg in Slack reviewer test double

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Co-authored-by: Johannes du Plessis <51395795+johannes117@users.noreply.github.com>
Co-authored-by: open-swe[bot] <johannes@langchain.dev>
2026-06-03 11:50:37 -07:00
Johannes du Plessis
1d4f1aed33
fix: reviewer publishes against stale head_sha on mid-run re-review (#1393)
* fix: resolve reviewer head_sha from thread metadata, not frozen run config

A push that lands while a reviewer run is in flight is delivered as a
queued message into that run. The run's configurable is frozen at
creation, so its head_sha still names the commit the run was created for
— not the commit just pushed. publish_review then anchored the GitHub
review to the stale commit and regressed last_reviewed_sha to it, and
add_finding/update_finding stamped findings with the stale SHA.

Persist the current head in thread metadata at every reviewer dispatch
(both the ready-for-review and push paths, before they branch to create
a run or queue a message), and add resolve_review_head_sha() which
prefers the metadata head over the run config. Wire it into
publish_review (review commit_id + last_reviewed_sha), add_finding
(first_seen_sha) and update_finding (last_confirmed_sha). Falls back to
the run config when metadata carries no head (first review, eval, tests).

* fix: persist head_sha in manual review dispatch (trigger_pr_review_from_ref)

resolve_review_head_sha prefers metadata[head_sha] over the run config,
and the push/ready dispatchers write it — but trigger_pr_review_from_ref
(Slack/GitHub @open-swe review, request_pr_review tool) created a run
with a freshly-fetched config head while leaving metadata's head stale
from a prior dispatch. A manual re-review at a newer commit would then
resolve to the old head and publish/advance findings against it.

Persist head_sha in that dispatch's metadata write too, so every
run-creating reviewer dispatch keeps metadata in sync with the head its
run targets. Caught by the Open SWE reviewer on this PR.
2026-06-03 11:38:56 -07:00
open-swe[bot]
ae946d1aa5 chore: attribute commit co-author to open-swe[bot], not open-swe user
The Co-authored-by trailer and bot git identity used
open-swe@users.noreply.github.com, which resolves to the separate
open-swe *user* account rather than the open-swe[bot] GitHub App.
Switch OPEN_SWE_BOT_EMAIL to the bot's noreply address
(215916821+open-swe[bot]@users.noreply.github.com) so co-author credit
and the fallback author identity point at the bot.

Drive the prompt trailer and sandbox git config from the constant
instead of hardcoding the address.
2026-06-03 11:19:24 -07:00
Johannes du Plessis
18f8ca56fb
fix: dedup empty reviewer summary by PR state, not stale re_review flag (#1391)
A push that lands while a reviewer run is in flight is delivered as a
queued message into the still-running first-review run, whose
configurable still has re_review=False. The empty-review guard in
publish_review only skipped the 'No issues found' summary when
is_re_review was True, so the queued reconcile published a second,
duplicate top-level 'No issues found' review.

Key the empty-review skip off actual PR state instead: add
open_swe_review_exists(), which detects the marker render_review_body
embeds in every Open SWE review body, and skip the summary when a prior
Open SWE review already exists (regardless of the re_review flag). Fails
open on API error so a genuine first review is never suppressed.
2026-06-03 10:30:13 -07:00
Johannes du Plessis
0a2e682364
fix: scope public reviewer tokens (#1389)
* fix: scope public reviewer tokens

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>

* refactor: simplify reviewer token wiring; fix push re-scope + red test

- Remove the redundant _check_or_recreate_sandbox_for_proxy /
  _refresh_github_proxy_or_recreate_for_proxy wrappers and call the
  underlying functions directly (they already default the token to None).
- process_github_push_event: re-scope the GitHub App token when the push
  payload lacked repo privacy/id but PR metadata reveals a public repo, so
  reviewer.py never proxies a full-installation token for a public PR.
- Clarify the two-token sequence in trigger_pr_review_from_ref.
- Fix pre-existing failing test test_proxy_refresh_failure_recreates_sandbox
  and add coverage for _reviewer_token_for_repo + push-event scoping.

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
2026-06-03 09:25:17 -07:00
Johannes du Plessis
c8a997c125
fix: reliable, safe Slack account-connect prompt + first-login Slack dialog (#1383)
* fix: deliver Slack account-link prompt as a visible threaded reply

Blocked Slack users got no prompt at all. Prod logs show chat.postEphemeral
returns ok, but ephemeral messages are silently dropped in Slack's assistant
threads (where Open SWE runs), so the user sees nothing. Post the prompt as a
normal threaded reply instead — the same channel the agent uses to reply.

* fix: deliver Slack auth-failure prompt as a visible threaded reply

leave_failure_comment() tried an ephemeral message first and only fell back
to a thread reply on failure. Ephemeral messages succeed (ok) but are dropped
in Slack's assistant threads, so the fallback never fired and the user saw no
auth-failure prompt. Post the visible threaded reply directly, matching the
account-link prompt fix.

* fix: prompt blocked Slack users with a generic, token-free dashboard link

Addresses the review findings that posting the per-user account-link token /
auth URL in a visible thread lets any channel member bind their GitHub account
to the triggering user's Slack identity.

Drop the per-user signed link entirely. Both the account-link prompt
(_post_account_link_prompt) and the runtime auth-failure prompt
(leave_failure_comment) now post a plain dashboard settings link
(build_settings_url) as a visible threaded reply. The user signs in with GitHub
from their own session and connects Slack via verified OIDC on the settings
page — no secret in the thread, nothing to hijack, and no DM machinery.

* feat: nudge first-time users to connect Slack from the dashboard home

Show a Connect Slack banner on the agents landing page whenever Slack OAuth is
enabled and the user hasn't linked Slack yet. A first-time user (no Slack
mapping) sees it immediately after signing in; it disappears once connected.

* feat: prompt first-time users to connect Slack via a dialog

Replace the inline Connect Slack card on the agents home with a modal dialog
(Base UI). It opens automatically once the mapping query resolves to
"not connected" and closes itself once Slack is linked; "Maybe later" dismisses
it for the session. No new dependency — uses the design system's Base UI.

* copy: frame Slack connect as resolving the user's GitHub account

Drop 'act/reply on your behalf' wording across the connect-Slack dialog, the
Slack thread prompts (blocked + auth-failure), and the settings description.
Connecting Slack lets Open SWE resolve the user's GitHub account when they tag
it in Slack.
2026-06-02 20:55:07 -07:00
Johannes du Plessis
046388a4e9
feat: simplify PR attribution footer to "Made by Open SWE" (#1382)
Replace the double-attribution PR body footer (_Opened collaboratively by
{user} and open-swe._) with a single Cursor-style footer linking to the
project. Since PRs are now opened as the triggering user, the user no longer
needs to be named in the footer. The commit Co-authored-by trailer is kept.

Legacy footers are migrated on PR updates.
2026-06-02 19:52:27 -07:00
Johannes du Plessis
5d033c7548
fix: clearer Slack prompt for users who must sign in with GitHub (#1380)
* fix: clearer Slack prompt for users who must sign in with GitHub

The Slack gate labeled any mapped-but-tokenless user as having an
"expired or revoked" authorization, keyed off whether a *mapping* row
existed. Most blocked users are team members in the legacy hardcoded
mapping who have simply never completed a dashboard GitHub login, so the
message was misleading and steered them toward reconnecting Slack (which
never creates a token).

Base the prompt on whether an oauth_tokens *record* exists:
- no record  -> ask the user to sign in with GitHub and connect Slack
- record but unusable -> ask the user to sign in with GitHub again

Add has_access_token_record() to distinguish the two cases.

* fix: guard token-record check so a store failure still prompts sign-in

The has_access_token_record() lookup ran outside the defensive handling
around token resolution. If the store read fails it would raise before
posting the sign-in prompt and clearing the Slack assistant status.
Wrap it like get_valid_access_token: on failure, default to the
sign-in/connect prompt.
2026-06-02 19:39:44 -07:00
Johannes du Plessis
04c346176d
feat: open PRs as the triggering user via dedicated tool (#1378)
Add an open_pull_request tool that creates a new PR via the GitHub REST
API using the triggering user's OAuth token (resolved by login from the
dashboard store), so the PR creator is the user rather than open-swe[bot].
Falls back to the GitHub App installation token for GitHub-triggered runs,
unmapped users, and bot-token-only deployments.

The user token never enters the sandbox: clone/push/comments still go
through the bot proxy via gh. The agent is steered to use the tool only
for OPENING a new PR; updates (body edits, mark ready) and pasted/existing
PRs continue to use gh pr edit. Existing-PR (422) returns the open PR's
URL so re-runs don't create duplicates.
2026-06-02 16:01:54 -07:00
Johannes du Plessis
cb4c643e43
feat: open Slack-triggered PRs as the triggering user (#1375)
* feat: open Slack-triggered PRs as the triggering user

Route the Slack per-user GitHub token through the dashboard OAuth store
(the backend the self-service link prompt populates) and block runs that
lack a valid user token, prompting the user to (re-)link. Per-user OAuth
now wins over bot-token-only mode for mapped Slack/dashboard users.

Flip commit/PR authorship across all sources: the triggering user is the
commit author (via repo-local git identity using their resolvable GitHub
noreply email) and open-swe[bot] is the Co-authored-by collaborator.

* fix: address PR review — shell-escape commit identity, fix token cache impersonation

- Shell-escape the triggering user's name/email with shlex.quote before
  embedding them in the repo-setup `git config` command, so a name like
  O'Connor (or a crafted one) can't break or inject into the command.
- Stop consulting the shared thread-metadata token cache in
  _resolve_dashboard_user_token. Slack thread ids are shared across the
  conversation, so a cached token from a prior triggering user could be
  returned for the current github_login. Always resolve by login from the
  dashboard OAuth store instead.

* feat: dashboard self-service user mapping + UI cleanup

- Add session-scoped GET/PUT /dashboard/api/my-mapping so users can set their
  own work email / Slack member ID (keyed by their GitHub login, source=self).
- Slack account-link prompt now redirects to Profile Settings after auth.
- Rename "My Settings" -> "Profile Settings" and "Cloud Agents" -> "Open SWE
  Agent"; remove the Integrations tab/section (folded out, low value for now)
  and redirect /integrations to Profile Settings.
- Add a "User mapping" section to Profile Settings (work email used by Slack
  and Linear, optional Slack member ID).
- Make dashboard auth cookies scheme-aware: Secure;SameSite=None over HTTPS,
  non-Secure;SameSite=Lax over http://localhost so local login works.

* feat: self-service Slack account linking via Sign in with Slack (OIDC)

Replace the spoofable manual work-email/Slack-ID form with a verified
"Sign in with Slack" flow so a logged-in GitHub user can only ever link
their own Slack identity.

- New agent/dashboard/slack_oauth.py: OIDC authorize URL, code exchange,
  userInfo identity parse, optional workspace gate, configured check.
- routes.py: session-gated GET /slack/login and /slack/callback that upsert
  the mapping from Slack-verified user_id + email (source=slack_oauth).
  Remove the spoofable PUT /my-mapping; expose slack_oauth_enabled on /me.
- UI: drop the editable inputs; add a Connect Slack button + status to the
  User mapping section.

Admin-managed mappings are unaffected and still resolve at trigger time.
2026-06-02 15:04:20 -07:00
open-swe[bot]
111f00ea9a
fix: include GitHub username in collaboration footer (#1374)
* fix: include GitHub username in collaboration footer

Co-authored-by: Johannes du Plessis <51395795+johannes117@users.noreply.github.com>

* fix: clarify legacy footer replacement

Co-authored-by: Johannes du Plessis <51395795+johannes117@users.noreply.github.com>

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Co-authored-by: Johannes du Plessis <51395795+johannes117@users.noreply.github.com>
2026-06-02 09:27:51 -07:00
Johannes du Plessis
7a9785c9d3
fix: resolve dashboard run email from GitHub mapping, not OAuth profile (#1372)
When sending a message to a thread from the Agents chat UI, the run used
the OAuth profile email (which can be a personal account that isn't an org
member). For Slack-originated threads resumed from the UI, auth routes
through the email-based path and fails ("Could not find a LangSmith account").

Resolve the run email via the GitHub->email mapping first, falling back to
the profile email only when no mapping exists, matching the github-source
auth path.
2026-06-01 15:47:53 -07:00
Johannes du Plessis
c41185a3ca
chore: remove legacy mapping + admin profiles section, page user mappings (#1371)
* chore: remove legacy mapping + admin profiles section, page user mappings

- Delete the hardcoded github_user_email_map.py and the one-time
  POST /admin/user-mappings/import endpoint + Import legacy mapping UI
  button (the Store is now the sole source of truth post-import).
- Remove the per-user profiles admin section and its GET/PUT
  /admin/profiles endpoints + ProfileForm component; users still manage
  their own profile via My Settings.
- Page the user mappings list: /admin/user-mappings now takes
  page/page_size and returns {items,total,page,page_size}; the admin UI
  shows 20 rows per page with Previous/Next controls.

* Address review: fix stale import-button doc + clamp mappings page on shrink
2026-06-01 22:10:55 +00:00
Johannes du Plessis
427bfe4f56
feat: Store-backed GitHub/Slack user mapping (self-service + admin) (#1369)
* Replace hardcoded GitHub-email map with Store-backed user mapping

Move the static GITHUB_USER_EMAIL_MAP to a Store-backed bidirectional
mapping (GitHub login <-> work email <-> optional Slack ID) with an
in-process cache, self-service onboarding, and admin management.

- agent/dashboard/user_mappings.py: Store CRUD + login/email/slack-id
  indexes, sync cache readers for hot paths, async fallthrough, and a
  bulk_import that preserves existing richer records.
- Migrate all read sites (auth.py, agent_overrides.py, authorship.py,
  github_comments.py, webapp.py x2) off the dict.
- Unmapped Slack tags now run on the GitHub App installation token
  (use_installation_token_fallback) and get an ephemeral "link your
  GitHub account" prompt carrying the Slack id + email via a signed
  account-link token threaded through the OAuth state.
- OAuth callback completes a self-service (org-gated) mapping from that
  token, falling back to the verified GitHub email.
- Admin CRUD endpoints + one-time legacy import; dashboard UI section.
- Legacy dict retained only as the import payload (no longer read).

Tests: mapping store, account-link round-trip + completion, mapped vs
unmapped Slack flows; existing trust-gate tests updated to prime cache.

* Address review: cold-cache email resolution + stale alias de-indexing

- agent_overrides: add resolve_login_from_email_async that falls through to
  the Store on a cold cache; use it at the async repo-resolution call sites
  (Slack repo config, Linear comment, owner-metadata) so a mapped user still
  resolves to their GitHub login + dashboard default_repo on a fresh worker.
- user_mappings.upsert_mapping: de-index the existing login before re-indexing
  so a changed email/Slack id no longer leaves stale aliases resolving to the
  login in-process.
- Tests for both fixes; update Slack repo-config test to patch the async resolver.
2026-06-01 14:37:19 -07:00
Johannes du Plessis
9a8b2d9984
feat: Inject PR title and body into reviewer context (#1368)
* Inject PR title and body into reviewer context

The reviewer agent previously received the PR url, number, and SHAs but not
the PR title or description, so it sometimes missed the original intent of
the PR. Fetch the title/body fresh from the GitHub API on every run (never
cached) so edits to the title/description are reflected on re-reviews, and
inject them into the first-review, re-review, and finding-reply contexts as
an untrusted-data block (author-controlled text, guarded against prompt
injection).

* Harden PR overview escaping against whitespace-padded closing tags
2026-06-01 21:06:19 +00:00
Johannes du Plessis
bed3eefbcb
fix: Lock dashboard login to GitHub org members (#1367)
* Lock dashboard login to GitHub org members

Add an org-membership gate to the dashboard OAuth callback. After
resolving the GitHub login, enforce_org_login_gate(login) checks the
existing ALLOWED_GITHUB_ORGS allowlist before issuing a session.

- Reuses ALLOWED_GITHUB_ORGS (no new config knob) and
  is_user_active_org_member (installation-token check, so no extra
  OAuth scope and private memberships are visible).
- Fail-open when unset/blank so existing deployments keep working;
  fail-closed on API errors.
- Gate runs before the session cookie/token is persisted.

Adds unit tests and documents the behavior in INSTALLATION.md.

* docs: document Organization Members permission required for org login gate
2026-06-01 20:56:30 +00:00
Johannes du Plessis
4a55145bb1
feat: outcomes dataset + bootstrap/continual split via skills (#1365)
* fix: reset stale sandbox creation sentinel

Co-authored-by: Johannes du Plessis <51395795+johannes117@users.noreply.github.com>

* fix: treat SANDBOX_CREATING as a timestamped cross-process lock

Only reset the sentinel when proven stale (older than the creation
timeout); otherwise wait for the worker that holds the lock so a
concurrent run does not create a duplicate sandbox.

* feat(analyzer): outcomes dataset + bootstrap/continual split via skills

Rename the review_style_analyzer graph to `analyzer` and split it into two
modes, plus capture reviewer finding outcomes for continual learning.

- Outcomes dataset: upsert resolved-by-commit (positive), dismissed (false
  positive), and GitHub/Slack thumbs findings into a single LangSmith dataset
  (openswe-reviewer-outcomes), keyed deterministically per finding+source.
  Emit points wired into update_finding, resolve_finding_thread, and the
  GitHub/Slack reaction handlers.
- Two playbooks delivered as deepagents skills (bootstrap-repo-analysis,
  continual-learning), served as virtual files via a CompositeBackend /skills/
  route + StateBackend (seeded into the run files channel at invoke time, never
  written to the sandbox). Mode is set by the launcher; continual runs fall
  back to the GitHub App installation token.
- Split launcher into start_bootstrap_analysis + start_continual_run; register
  a per-repo nightly continual-learning cron when bootstrap completes.
- New read_finding_outcomes tool feeds confirmed/dismissed findings back to the
  continual playbook.

Tests for outcome label mapping, skills helper, and cron idempotency.

* fix(analyzer): anchor continual cron runs to a real thread_id

The nightly continual-learning cron is threadless, and get_analyzer
early-returns an empty agent when configurable.thread_id is missing — so
every cron-launched run no-op'd before reading outcomes or saving a refined
prompt. Include the repo's deterministic analyzer thread_id in the continual
run configurable so the run executes; the threadless run carries no message
history, so nightly runs don't accumulate context.

* refactor(analyzer): move cron lifecycle calls out of the review-styles store

Drop the inline `analyzer_cron` imports from review_styles.py (added only to
dodge a circular import) by relocating the cron-trigger calls to the layer
above the store: registration to the save_review_style tool (after a prompt is
saved) and removal to the dashboard delete route. review_styles.py is now a
pure store again with top-level imports only.

* refactor: hoist reviewer_outcomes imports to module level

Move the two inline emit_finding_status_outcome imports introduced in this PR
(update_finding, resolve_finding_thread) to top-level imports. reviewer_outcomes
only depends on langsmith, so there is no circular import to avoid.

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
2026-06-01 13:25:12 -07:00
Johannes du Plessis
015476230c
feat: surface all of a user's agent threads in the Agents UI (#1366)
* feat: surface all of a user's agent threads in the Agents UI

Previously the Agents UI only listed and allowed opening threads with
source=dashboard. Threads triggered from GitHub, Slack, or Linear were
hidden and could not be opened.

- Persist owner-identifying metadata (source, github_login,
  triggering_user_email, source_context) onto the thread for each
  webhook-triggered main-agent run via upsert_agent_thread_owner_metadata,
  resolving a github_login from the triggering email where possible.
- Relax dashboard thread listing/ownership to surface github/slack/linear
  threads owned by the logged-in user (matched by github_login or email),
  and preserve the original source + reply-routing context when continuing
  such threads from the UI.
- Add a source field to the thread summary and render a source icon
  (GitHub/Slack/Linear) on thread items in the sidebar and run cards.

* Normalize triggering email when persisting thread owner metadata

Mixed-case Slack/Linear emails were stored verbatim, but the dashboard
searches with a lowercased value, so those threads never surfaced for
their owner. Normalize at write time to match _thread_owner_email.
2026-06-01 13:01:20 -07:00
open-swe[bot]
dcef5ff71e
fix: preserve pushed commit history (#1360)
* fix: preserve pushed commit history

Co-authored-by: Johannes du Plessis <51395795+johannes117@users.noreply.github.com>

* refactor: consolidate no-force-push prompt guidance

Collapse the repeated force-push rule into a single IMPORTANT block,
drop the confusing rebase-onto-origin step, and stop mandating a
no-op trailer-only commit for already-pushed work.

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Co-authored-by: Johannes du Plessis <51395795+johannes117@users.noreply.github.com>
Co-authored-by: Johannes du Plessis <johannes@langchain.dev>
2026-05-29 15:07:18 -07:00
open-swe[bot]
8130a188ef
chore: bump deepagents to 0.6.6 (#1359)
* chore: bump deepagents to 0.6.6

Co-authored-by: Mason Daugherty <61371264+mdrxy@users.noreply.github.com>

* chore: remove obsolete deepagents reducer patch

Co-authored-by: Johannes du Plessis <51395795+johannes117@users.noreply.github.com>

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Co-authored-by: Mason Daugherty <61371264+mdrxy@users.noreply.github.com>
Co-authored-by: Johannes du Plessis <51395795+johannes117@users.noreply.github.com>
2026-05-29 11:08:55 -07:00
open-swe[bot]
65acc4c9d3
fix: sanitize malformed Anthropic thinking blocks (#1357)
Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Co-authored-by: Johannes du Plessis <51395795+johannes117@users.noreply.github.com>
2026-05-28 16:15:13 -07:00
open-swe[bot]
eb92947806
fix: propagate Slack reply errors (#1358)
* fix: propagate Slack reply errors

Co-authored-by: Johannes du Plessis <51395795+johannes117@users.noreply.github.com>

* fix: classify Slack 429 as rate_limited with retry-after

Slack chat.postMessage rate limiting returns HTTP 429, which raise_for_status
turned into a generic http_error and told the agent to retry immediately,
ignoring Slack's retry window. Special-case 429 (threading Retry-After) and
normalize the ratelimited body code before the generic HTTP path so the
existing rate_limited hint actually fires.

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Co-authored-by: Johannes du Plessis <51395795+johannes117@users.noreply.github.com>
Co-authored-by: Johannes du Plessis <johannes@langchain.dev>
2026-05-28 23:11:42 +00:00
open-swe[bot]
a361ee8f2e
feat: let reviewer set comment titles (#1356)
Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Co-authored-by: Johannes du Plessis <51395795+johannes117@users.noreply.github.com>
2026-05-28 16:04:38 -07:00
open-swe[bot]
9998119921
feat: generate reviewer finding titles (#1355)
Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Co-authored-by: Johannes du Plessis <51395795+johannes117@users.noreply.github.com>
2026-05-28 15:28:55 -07:00
Johannes du Plessis
a2a1692493
Remove reviewer env allowlist (#1353) 2026-05-28 14:29:33 -07:00
open-swe[bot]
d8d3794649
fix: include reviewer trace links (#1351)
* fix: include reviewer trace links

Co-authored-by: Johannes du Plessis <51395795+johannes117@users.noreply.github.com>

* feat: move reviewer trace-link toggle to dashboard

Replace the OPEN_SWE_REVIEW_TRACE_LINK_ENABLED env var with a team-level
'Trace Links' toggle in the Open SWE Review dashboard tab. The toggle is
read per-publish via get_team_review_trace_links_enabled(); the per-run
review_trace_link_enabled config override still forces it off.

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Co-authored-by: Johannes du Plessis <51395795+johannes117@users.noreply.github.com>
Co-authored-by: Johannes du Plessis <johannes@langchain.dev>
2026-05-28 13:48:14 -07:00
Johannes du Plessis
fee209601b
feat: structured reviewer comments + auto resolution comments (#1352)
* feat: structured reviewer comments + auto resolution comments

Restructure inline review comment bodies (severity emoji, bold title from
the first line, line reference, feedback footer) without duplicating the
first description line, and post an automatic resolution/dismissal comment
to the GitHub thread when a finding is resolved or dismissed.

- Centralize render_resolution_comment in reviewer_publish; fix a crash when
  last_reconciliation_note is None and drop the misleading generic fallback.
- Post the resolution comment in resolve_finding_thread (the normal
  update_finding path), not only in publish_review, so it actually fires on
  re-review. Dedupe via github_posted_resolution_comment_ids.
- Add pytest coverage for rendering and the resolution-comment flow.

* fix: post resolution comment to every closed thread in resolve_finding_thread

Per-thread iteration (matching _resolve_threads_for_resolved_findings) so
duplicate threads after the first also receive the resolved/dismissed
explanation before being closed.
2026-05-28 12:44:00 -07:00
Johannes du Plessis
4e6c445246
feat: upgrade default agent + reviewer model to Opus 4.8 (#1350)
* feat: upgrade default agent + reviewer model to Opus 4.8

Replace Opus 4.7 with Opus 4.8 (claude-opus-4-8) as the supported
Anthropic model surfaced in the profile editor and used by the main
agent and reviewer graphs. Effort levels (low/medium/high/xhigh/max)
and the high default are unchanged, matching the official Opus 4.8
docs. Updates eval config comment and tests accordingly.

* fix: provider-aware fallback for stale stored model ids

Dropping claude-opus-4-7 from the supported set meant persisted
profile/team-settings still holding it failed the SUPPORTED_MODEL_IDS
check and fell through to default_model_pair() — a cross-provider jump
to the OpenAI global default.

Add provider_fallback_pair: when a stored id is no longer supported but
its provider still has a supported model, resolve to that provider's
newest supported model (anthropic:claude-opus-4-7 -> 4.8), preserving
effort when valid. Resolution order is now: valid stored pair ->
same-provider fallback -> global default_model_pair(). Profile overrides
keep deferring to the team default when no model is set or the provider
is unknown.
2026-05-28 10:59:29 -07:00