Commit graph

780 commits

Author SHA1 Message Date
musistudio
240cd73c1c Merge branch 'dev/3.1' into dev/docs
# Conflicts:
#	docs/src/content/docs/en/configuration/profiles.md
#	docs/src/content/docs/zh/configuration/profiles.md
2026-08-06 14:16:12 +08:00
musi
3c71252de1 Add interactive docs demos 2026-08-06 14:10:32 +08:00
musistudio
89081a2082 Preserve target-provider slash model routing 2026-08-06 14:07:56 +08:00
musistudio
94674ba2e6 Add web content JSON provider account connectors 2026-08-06 11:36:11 +08:00
musistudio
b4e6185172 Separate enhanced route from profile routing settings 2026-08-05 20:23:08 +08:00
musistudio
df42fe8683 Propagate provider context for Fusion model discovery 2026-08-05 20:06:58 +08:00
musistudio
9943ab273b docs: update desktop download links for v3.0.19 2026-08-05 19:52:54 +08:00
musistudio
b41890610c chore: release v3.0.19 2026-08-05 18:58:13 +08:00
musistudio
0fd7bf755f Merge dev/3.1 into main for v3.0.19
# Conflicts:
#	packages/ui/src/pages/home/components/network-logs.tsx
2026-08-05 18:56:16 +08:00
musistudio
39430f4f9d Update ai-gateway to 1.0.16 2026-08-05 18:53:34 +08:00
musistudio
62ca009716 feat: update ai-gateway version 2026-08-05 16:48:24 +08:00
musistudio
0e1d9f4c05 Add Codex multi-agent bridge and provider model descriptions 2026-08-05 16:24:36 +08:00
musistudio
b4afa55c49 Offload large network log body formatting to a web worker 2026-08-05 15:49:18 +08:00
musistudio
561c2d813c Add local agent auth provider hook support 2026-08-04 15:34:47 +08:00
musistudio
4cba6b51a8 Apply provider capability routing per upstream attempt 2026-08-04 10:21:51 +08:00
musi
d09dd7b6cb Update provider and agent configuration guides 2026-08-04 09:19:14 +08:00
musi
bc8a8e6205
Merge pull request #1618 from NDViet/main
fix(ui): repair provider setup flow in Get Started onboarding
2026-08-03 13:20:37 +08:00
musi
7a51e892cc
Merge pull request #1622 from jesieleo/fix/codex-oauth-live-credentials
fix(codex): 同步本地登录的最新 OAuth 凭据
2026-08-03 13:20:24 +08:00
musi
79ed74b38f
Merge pull request #1626 from pacocartones/fix/api-key-timing-safe-comparison
fix(gateway): compare API keys in constant time
2026-08-03 13:20:09 +08:00
musi
454daec31c Improve documentation navigation and extension guidance 2026-08-03 08:40:36 +08:00
pacocartones
174ab41849 fix(gateway): compare API keys in constant time
The gateway API key authorizer matched the presented token against every
configured key with `item.key === token`, a variable-time string
comparison that returns on the first differing byte. The repository
already avoids that shape for its other secrets: context-archive.ts,
management-server.ts and media/service.ts each compare tokens through a
local timingSafeEqual helper with a length guard.

Route the gateway API key lookup through the same helper shape so all
secret comparisons behave identically. The length guard is kept so a
token of a different length is rejected rather than making
timingSafeEqual throw.

Behaviour is unchanged: valid keys authorize, unknown keys still return
401 "Invalid API key.", expired keys still return 401 "API key is
expired.", and the refresh-on-miss reload path is preserved.
2026-08-02 19:41:27 +02:00
musi
bd9ffd385c
Merge pull request #1623 from jesieleo/fix/ui-responsive-overflow
fix(ui): 修复窄窗口下侧栏和账户卡片内容被遮挡的问题
2026-08-02 17:09:36 +08:00
musi
991b04fde6
Merge pull request #1621 from mindops/codex/show-routed-model-logs
fix: show routed model in request logs
2026-08-02 17:06:44 +08:00
musi
1a66077df8
Merge pull request #1620 from ezra-quemuel/fix/codex-provider-protocol-capability
fix(config): Codex provider requests 404 — top-level protocol never became a capability
2026-08-02 16:18:30 +08:00
jesieleo
440241faa0 fix(ui): prevent responsive panels from clipping content 2026-08-02 12:46:10 +08:00
jesieleo
c86e86038a fix(codex): refresh OAuth credentials from local login 2026-08-02 12:46:00 +08:00
willyang
9331c9cbef fix: show routed model in request logs 2026-08-01 16:22:06 +08:00
ezra-quemuel
24a4861aa6 fix(config): translate top-level provider protocol into a capability
Local-agent login imports (Codex API et al.) declare the provider protocol
at the top level of the payload (protocol: "openai_responses") and carry no
capabilities array. parseProviders dropped that field, so the saved provider
ended up with neither protocol nor capabilities and the gateway fell back to
the default openai_chat_completions adapter. For Responses-only backends
(chatgpt.com/backend-api/codex) every request then 404s against a
non-existent /chat/completions route.

Synthesize a single capability from the top-level protocol (and the
provider's base URL) when no explicit capabilities are configured, reusing
the existing protocol normalization used for capability items. Explicit
capabilities still win. Fixes #1619.
2026-07-31 17:24:39 -07:00
Viet Nguyen Duc
ba80cc81eb
fix(ui): repair provider setup flow in Get Started onboarding
The onboarding wizard and the Add/Edit Provider dialog render the same
AddProviderForm, but the wizard is wired up differently, and several
defects lived in those differences.

Model probe never fired during onboarding. The model-probe useEffect in
App.tsx guarded on `providerAddOpen` only, which is set true solely when
opening the manual Add/Edit Provider dialog. It is never set during the
onboarding wizard, so after entering an endpoint + API key on the Get
Started flow and reaching the "Pick models" step,
probeProviderCandidates() never fired and the model list stayed empty
with no loading state. Regressed in 9f704fc ("Guide onboarding through
granular provider setup steps"), which narrowed the guard from
`providerAddOpen || (activeView === "onboarding" && onboardingStep === "provider")`
down to `providerAddOpen`. Restore the broader guard so the probe runs
both when the dialog is open and when onboarding is on the provider step.

A rejected API key produced an empty model list with no feedback. Typing
an API key switches the probe from mode "protocols" to mode "models",
but the error-reporting branch was guarded on `probeMode !== "models"`,
so it never ran in exactly that mode. The backend still runs full
protocol probing in models mode, so a 401 came back as `supported: false`
with a real message that was then discarded. Report the failure, while
staying quiet when models were discovered, since a provider can expose a
working catalog while a protocol probe endpoint 404s.

"Added models" faked a loading state for data it already had. The panel
renders local draft state, yet showed a skeleton and hid its whole
toolbar whenever the catalog probe re-ran, leaving the header badge
reading a real count above shimmer rows and removing the "Custom model"
button, the only way to add models on a provider with no catalog. Keep
both panels' controls mounted, disabling the catalog search while
loading, which also removes a layout shift and mid-typing focus loss.

An empty catalog gave no way forward, so point at "Custom model" (en+zh).

Onboarding's "Check Connection" spent real credits with no confirmation.
The dialog wraps onCheck in a confirm step that warns about account
balance, lets the user pick models, and shows per-model results;
onboarding passed onCheckProvider straight through, so one click fired a
billable request against every configured model and discarded the
report. Extract that step as ProviderConnectivityCheckDialog and use it
from both surfaces.

ProviderConnectionStatusRow hardcoded bg-emerald-50 / border-emerald-200
/ bg-amber-50 with no dark variant, so the "Verify connection" status
chips rendered as bright light blobs on the dark card. Use alpha fills,
matching the pattern used elsewhere in the file.

The provider error banner was not announced; add role="alert".

Signed-off-by: Viet Nguyen Duc <nguyenducviet4496@gmail.com>
2026-08-01 06:47:14 +07:00
musistudio
ccf63088ea Fix Bot Gateway stdio runner handling in Electron 2026-07-31 17:25:33 +08:00
musistudio
4a152d959c feat: update ai-gateway version
Some checks failed
Docs / Build (push) Has been cancelled
Docs / Deploy (push) Has been cancelled
2026-07-31 15:39:56 +08:00
musistudio
6a3509dbb2 Merge dev/3.1 into main for v3.0.18 2026-07-31 15:37:47 +08:00
musistudio
e8ae64f5a2 feat: update ai-gateway version 2026-07-31 15:33:46 +08:00
musistudio
3f566d991a Preserve API keys across provider probes 2026-07-31 14:50:19 +08:00
musistudio
39a5712ae7 Prepare Claude App VM storage before launch 2026-07-31 11:55:10 +08:00
musi
7aa18a0c49 Merge branch 'refs/heads/dev/3.1' into dev/docs 2026-07-31 08:36:48 +08:00
musistudio
43f99b2de8 Use Token consistently in Chinese UI labels 2026-07-30 18:44:03 +08:00
musi
2bceead04b
Merge pull request #1605 from ShiroKSH/fix/abort-retry-backoff
fix(gateway): abort retry backoff on disconnect
2026-07-30 17:33:09 +08:00
musistudio
571aa63602 Show request and trace costs in agent observability 2026-07-30 17:32:34 +08:00
musi
1bf0e2e690
Merge pull request #1604 from matteoantoci/fix/claude-code-keychain-account
fix(claude-code): look up the macOS keychain item by account
2026-07-30 15:46:13 +08:00
musistudio
7b6a14301c Refine subagent model extraction and add detection tests 2026-07-30 15:29:56 +08:00
musistudio
e778687774 Show partial agent session failures in observability UI 2026-07-30 15:25:50 +08:00
musi
ca3563ae66 Merge branch 'dev/3.1' into dev/docs
# Conflicts:
#	README.md
#	README_zh.md
#	docs/src/content/docs/en/agentclaw/weixin-ilink.md
#	docs/src/content/docs/en/configuration.md
#	docs/src/content/docs/en/configuration/bot-setup.md
#	docs/src/content/docs/en/configuration/extensions.md
#	docs/src/content/docs/en/configuration/profiles.md
#	docs/src/content/docs/en/configuration/routing.md
#	docs/src/content/docs/en/guides.md
#	docs/src/content/docs/en/guides/agent-profile.md
#	docs/src/content/docs/en/guides/cli.md
#	docs/src/content/docs/en/index.md
#	docs/src/content/docs/en/troubleshooting.md
#	docs/src/content/docs/zh/agentclaw/dingtalk.md
#	docs/src/content/docs/zh/agentclaw/discord.md
#	docs/src/content/docs/zh/agentclaw/feishu.md
#	docs/src/content/docs/zh/agentclaw/line.md
#	docs/src/content/docs/zh/agentclaw/slack.md
#	docs/src/content/docs/zh/agentclaw/telegram.md
#	docs/src/content/docs/zh/agentclaw/wecom.md
#	docs/src/content/docs/zh/agentclaw/weixin-ilink.md
#	docs/src/content/docs/zh/configuration.md
#	docs/src/content/docs/zh/configuration/bot-setup.md
#	docs/src/content/docs/zh/configuration/profiles.md
#	docs/src/content/docs/zh/configuration/providers.md
#	docs/src/content/docs/zh/configuration/routing.md
#	docs/src/content/docs/zh/guides.md
#	docs/src/content/docs/zh/guides/agent-profile.md
#	docs/src/content/docs/zh/guides/cli.md
#	docs/src/content/docs/zh/index.md
#	docs/src/i18n/content.ts
#	docs/src/pages/configuration/[slug].astro
#	docs/src/pages/en/configuration/[slug].astro
#	docs/src/pages/en/guides/[slug].astro
#	docs/src/pages/guides/[slug].astro
2026-07-30 12:40:44 +08:00
ShiroKSH
7fcdeef78a fix(gateway): restore retry executor 2026-07-29 16:00:33 +03:00
ShiroKSH
546719003c fix(gateway): abort retry backoff on disconnect 2026-07-29 15:58:35 +03:00
Matteo Antoci
70d31ab47e fix(claude-code): never resolve a token from inside mcpOAuth
Review on #1604: preferring `claudeAiOauth` was not enough. A record holding
only `mcpOAuth` entries still produced a token, because the fallback ran a
recursive `findOauthTokenSet()` over the whole record and `mcpOAuth`
per-plugin records carry their own `accessToken`. That imports a plugin
token as a Claude Code provider and recreates the 401 the change was meant
to avoid. It also short-circuited the plaintext-file fallback, so a usable
`~/.claude/.credentials.json` was ignored in favour of the plugin token.

Restrict both lookups to root-level token fields instead of reordering the
recursive search. Root-level excludes *any* nested container, so a future
sibling of `mcpOAuth` cannot reintroduce the hole, and the pre-`claudeAiOauth`
layout that kept tokens at the record root still resolves.

Extract `readOauthTokenSetFields()` out of `findOauthTokenSet()` in shared.ts
rather than duplicating the field list. `findOauthTokenSet()` keeps its
behaviour, so codex/grok/kimi/opencode/zcode are unaffected.

Apply the same restriction to the credentials-file path: Claude Code writes
that file with the identical record shape, mcpOAuth included, so the hazard
was present there too.

Adds the two regression tests from the review verbatim.

Refs #1601, #1567
2026-07-29 14:34:09 +02:00
musistudio
e9bbf9dbb0 Synchronize legacy profiles with global profile state 2026-07-29 20:25:49 +08:00
musistudio
ea501e95f3 Fix deck-stage captures and Windows SDK path resolution 2026-07-29 19:04:41 +08:00
Matteo Antoci
519b92d406 fix(claude-code): look up the keychain item by account
Claude Code >= 2.1 writes its credential item under the current $USER and
leaves any pre-2.1 item (account "unknown") in place on the *same* service
name, `Claude Code-credentials`. `security find-generic-password -s <svc> -w`
with no `-a` matches an arbitrary one of them, so CCR read the stale legacy
item: the read exits 0, the JSON parses, and it carries only `mcpOAuth`.
`findOauthTokenSet()` then correctly returns undefined and the candidate is
silently dropped by the `status !== "missing"` filter in service.ts.

Resolve the item through tiered candidates, evaluated lazily so the normal
case stays at one `security` call:

1. the expected service name, derived the way Claude Code derives it
   (`Claude Code${oauthSuffix}-credentials${configSuffix}`, where
   configSuffix is `-${sha256(NFC(configDir)).slice(0, 8)}` once
   CLAUDE_CONFIG_DIR / CLAUDE_SECURESTORAGE_CONFIG_DIR is set), read under
   the current account;
2. `security dump-keychain` enumeration, newest-modified first, for items
   under another account or a config dir this process cannot reconstruct.
   Without `-d` that prints item metadata only: it never decrypts a
   password and never prompts;
3. the previous accountless read, as a last resort.

Prefer an explicit top-level `claudeAiOauth` across every candidate and fall
back to the recursive search only if none has one. `mcpOAuth` holds
per-plugin OAuth records that also carry `accessToken`, and key order puts
it first, so a recursive match could import an MCP plugin token as an
Anthropic provider that then 401s on every request.

Surface diagnostics instead of swallowing them: capture `security` stderr
rather than discarding it via `stdio: ["ignore","pipe","ignore"]`, and
return a `locked` candidate naming the reason when login state exists but
yields no token, so it survives the `status !== "missing"` filter. Treat
errSecItemNotFound (exit 44) as absence rather than an error, so a machine
with no Claude Code login still reports `missing`.

Also fix the file fallback: continue past a credentials file that holds no
token instead of returning it, and check the secure-storage config dir,
which the env vars above can relocate away from ~/.claude.

Refs #1601, #1567
2026-07-29 11:53:30 +02:00
musistudio
58523a1b04 Improve gateway runtime compatibility and child error diagnostics 2026-07-29 17:06:21 +08:00