Skip to content

Add OAuth provider flows and agent runtime fixes#58

Merged
ZYKJShadow merged 19 commits into
masterfrom
fix/agent-ui
Apr 26, 2026
Merged

Add OAuth provider flows and agent runtime fixes#58
ZYKJShadow merged 19 commits into
masterfrom
fix/agent-ui

Conversation

@ZYKJShadow
Copy link
Copy Markdown
Owner

Summary

  • Add OAuth login and runtime support for Codex, Claude Code, and Antigravity, including provider identity presets, model discovery, persisted OAuth auth, and settings UI integration.
  • Align Claude Code OAuth requests with CLIProxyAPI: official Anthropic base URL, Bearer auth, Claude Code headers, signed billing/body cloaking, OAuth diagnostics, and explicit stream error handling.
  • Align Codex OAuth model/request handling and Antigravity login/project/model/usage flows with the reference implementation.
  • Add Feishu user OAuth support plus native document, folder, task, and user lookup tools for bot integrations.
  • Improve agent/chat behavior around file revert snapshots, tool/runtime handling, thread reply indicators, chat scrolling, and related UI polish.

Verification

  • npm run typecheck
  • npx vitest run main-src/llm/providerIdentity.test.ts main-src/llm/modelResolve.test.ts
  • npm run build:main

ZYKJShadow and others added 19 commits April 25, 2026 22:29
…ding isAwaitingReply in light rows and tracking local streamingThreadId
…h to POSIX-only on Windows, fix URL/local-path detection

Task* tools (TaskCreate / TaskList / TaskGet / TaskOutput / TaskUpdate / TaskStop)
take over from TodoWrite. They are not a todo list — they are thin handles over
the existing managedSubagents runtime: TaskCreate spawns a sub-agent in the
background and returns immediately, then the model can poll/inspect/drive/cancel
via the other five. Prompt guidance now explicitly tells the model NOT to use
TaskCreate as a personal todo list, removing the old "proactive TodoWrite"
nudges that caused the model to write task lists for trivial work. The legacy
TodoWrite tool definition is removed from the model surface but its executor
case is kept so historical thread transcripts still parse.

Bash tool now requires POSIX bash on every platform. detectShell prefers Git
Bash / MSYS2 / Cygwin / WSL on Windows and refuses to fall back to PowerShell
for the LLM tool — the prompt and tool description no longer have any
"Windows uses PowerShell / avoid sed/awk" caveats, and the Windows-side Unix
command interceptor in the executor is gone. PowerShell provider is kept for
the built-in terminal profiles only.

AgentRightSidebar URL normalization no longer treats Windows drive paths as
URL schemes (`D:\foo`, `C:/bar` were being opened as protocols, then read_page
hung). The scheme regex now requires 2+ chars, and an explicit
local-filesystem-path detector routes such inputs to a Bing search.

Bottom-bubble CSS: clamp long user messages to a few lines with an ellipsis
instead of the previous scrollable max-height layout.

All 563 vitest tests pass; tsc --noEmit is clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds 11 Feishu-specific platform-scoped tools available only when an
integration has platform === 'feishu' and valid app credentials. Tools
are mounted as a per-turn bundle inside the bot leader pool, so other
platforms (Telegram/Slack/Discord) never see them.

Tools:
  Tasks (4):     list_feishu_tasks, create_feishu_task,
                 update_feishu_task, delete_feishu_task
  Contacts (1):  get_feishu_users (search by name OR batch by id)
  Documents (4): create_feishu_document, get_feishu_document_blocks,
                 batch_create_feishu_blocks, search_feishu_documents
  Folders (2):   get_feishu_folder_files, create_feishu_folder

Document/folder tools work with tenant_access_token. Task and contact
tools require user_access_token; they are filtered out of the leader
tool pool when the integration has no user token, so the LLM never
sees a tool it cannot successfully call.

A compact block-descriptor -> Feishu docx_v1 payload converter covers
text/heading/list/code/quote/divider/callout, sized for what an agent
actually needs to write. The 681-line upstream blockFactory is not
ported.

OAuth flow:
  - feishu:runOauth IPC binds a local HTTP callback server on
    127.0.0.1 with a fixed port chain [53782, 53783, 53784],
    opens accounts.feishu.cn/.../authorize via shell.openExternal,
    awaits the redirect with state CSRF check + 5-minute timeout,
    exchanges the code via client.authen.oidcAccessToken.create,
    fetches open_id and display name via authen.userInfo, persists
    tokens via a new updateBotIntegrationFeishuTokens helper that
    writes settings.json in place without round-tripping through
    the renderer.
  - feishuApiClient owns a mutable token holder. Before every
    user-token call it checks expiresAt against a 60-second leeway
    and serializes refresh through a single in-flight Promise to
    coalesce concurrent callers. On 99991661/99991663/99991664 it
    runs one forced refresh and retries the failed request once.
    Refreshes are persisted via an onTokensRefreshed callback wired
    from botRuntime to settingsStore.
  - feishu:cancelOauth aborts an in-flight flow; feishu:disconnect
    clears tokens; feishu:getCallbackUrls exposes the three URLs the
    user needs to allowlist in their Feishu app.

UI: SettingsBotsPanel grows a FeishuAuthSection with a status pill
("Not authorized" / "Authorized as Alice · 1h45m remaining"), an
Authorize button (disabled until appId/appSecret are filled), a
cancel button while the flow is open, a disconnect link, and inline
hints listing the three required redirect URLs and the required
Feishu scopes (task:task, contact:user.base:readonly). A 30-second
tick re-renders the remaining-time label.

Leader prompt: when feishu tools are mounted, the orchestrator system
prompt explicitly instructs the LLM to use them only on user-driven
Feishu requests, not to advertise them spontaneously, and surfaces a
different tool list depending on whether user_access_token is present.

Type changes: FeishuBotConfig grows userRefreshToken,
userAccessTokenExpiresAt, userAuthorizedOpenId, userAuthorizedName.
Twin types in main-src/botSettingsTypes.ts and src/botSettingsTypes.ts
stay in lockstep.

Tests: 7 new files / 50 cases under main-src/bots/platforms/feishu.
Coverage includes platform scoping, per-tool argument shaping,
pagination, nested subtask creation with per-path error capture,
search-vs-batch user lookups, OAuth state mismatch, timeout, cancel,
exchange failure, and refresh + retry-on-401 in the API client.
Also includes a small unrelated provider-identity settings tweak
that was already staged.

All 99 vitest files / 613 tests pass; tsc --noEmit is clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Append OAuth login providers instead of replacing existing accounts.

Group manual and OAuth providers in settings and show login failures via toast.

Use the system browser for legacy Codex login and add provider expand animations.
Force OAuth providers to use their matching runtime identities, repair Antigravity project discovery and fallback behavior, and remove Async-specific Codex login artifacts.
Agent write-file snapshots used to live only in `agentRevertSnapshotsByThread`
in main memory, so an app restart silently emptied the map. The renderer
ignored the backend's `reverted: 0` reply and hid the file-changes panel
anyway, leaving the on-disk edits intact while pretending the user had
rolled them back.

This change makes revert actually work across restarts and stops faking
success when it cannot:

* New `agentSnapshotStore` writes each thread's snapshots to
  `{userData}/async/agent-snapshots/{threadId}.json` via atomic
  tmp+rename. `initAgentSnapshotStore` repopulates the in-memory map at
  app boot.
* Every snapshot mutation now flushes to disk: `beforeWrite` hook,
  per-turn reset in `runChatStream`, and the keep/revert/seed/accept-hunk
  /revert-hunk IPC handlers. `threads:delete` clears the matching file.
* New `agent:hasSnapshots` IPC lets the renderer learn the truly
  revertable path set so the panel can disable buttons that would no-op.
* `useAgentPatchActions` now inspects `reverted` from `agent:revertLastTurn`
  / `agent:revertFile`. When zero, it skips the dismiss/persist path and
  raises a notice instead. The panel renders a warning banner and greys
  out revert buttons with a tooltip explaining the snapshot is gone.
* App refreshes the revertable set on thread switch and after each turn
  finishes (awaiting-reply true→false transition).
* Adds en/zh i18n strings for the new banner / tooltip / dismiss button.
@ZYKJShadow ZYKJShadow merged commit f89a403 into master Apr 26, 2026
1 check passed
@ZYKJShadow ZYKJShadow deleted the fix/agent-ui branch April 26, 2026 06:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant