Commit Graph

11233 Commits

Author SHA1 Message Date
Arvin Xu c9325794e5 🐛 fix(portal): close empty local file preview (#15760) 2026-06-13 16:31:56 +08:00
Innei 4a11ed9887 ♻️ refactor(auth): migrate auth pages to a standalone lightweight SPA (#15689)
*  feat(oidc): add interaction details endpoint

*  feat(auth-spa): scaffold standalone auth SPA shell and build pipeline

* 🐛 fix(auth-spa): address review findings in AuthShell copies

*  feat(auth-spa): add spa-auth html route handler

* ♻️ refactor(auth-spa): migrate simple auth pages into auth SPA

* 🔒 fix(auth-spa): validate locale segment in spa-auth route

* ♻️ refactor(auth-spa): move verify-im route to main SPA

* 🔒 fix(auth-spa): sanitize callbackUrl, fix signup form wiring, add router error element

* ♻️ refactor(auth-spa): migrate oauth pages into auth SPA

* 🐛 fix(auth-spa): address oauth migration review findings

* ♻️ refactor(auth): route auth pages to standalone SPA and drop Next auth tree

* 🔒 fix(auth): validate locale before middleware rewrite

* 🔥 chore(auth-spa): drop unused messenger i18n namespace from auth shell

* ️ perf(build): share one react vendor bundle across web/mobile/auth SPA builds

Build react core (react, react-dom, react-dom/client, react/jsx-runtime)
once as a self-contained ESM bundle under /_spa/vendor-shared, then mark
those specifiers external in every SPA build and map them via rolldown
output.paths to the same hashed URLs, so the auth page warms the main
app's react cache. react-router-dom stays per-build: apps use ~19K of it
after tree shaking while a shared bundle must export all 252K.

Also split auth i18n namespaces into per-locale chunks, keep locale
runtime helpers out of the default locale chunk, and group packages/const
into app-const so vendor-ai-runtime no longer captures it.

* ♻️ refactor(spa): extract shared SPA html serving helpers

Both the main SPA and auth SPA route handlers duplicated the Vite dev
asset rewriting, analytics config assembly and html template rendering.
Move them into src/server/spaHtml.ts; the desktop umami block becomes an
opt-in flag only the main SPA enables.

* 🐛 fix(auth-spa): bundle default locale resources and disable i18n suspense to fix signin mount loop

*  feat(auth-spa): wrap auth shell with BusinessAuthProvider slot

* 👷 build(spa): support custom vite dev origin and mark SPA entries side-effectful

* 🔥 chore: drop dead /welcome entry from nextjsOnlyRoutes

* 🐛 fix(auth-spa): forward referral to signup and fix error boundary dark-mode contrast

* ♻️ refactor(spa): lift NextThemeProvider above RouterProvider so route error boundaries are theme-aware

* update
2026-06-13 16:15:04 +08:00
Arvin Xu be7b759820 🛠️ chore(agent-testing): add local dev env bootstrap (#15757) 2026-06-13 13:54:13 +08:00
Arvin Xu fa76928f62 🐛 fix: fix Codex resumed usage reporting for heterogeneous agents (#15751)
🐛 fix(heterogeneous-agent): normalize codex resumed usage
2026-06-13 13:34:41 +08:00
Arvin Xu f6db1361ee feat(agent): show topic sidebar status indicators (#15739) 2026-06-13 13:32:56 +08:00
Arvin Xu 5d6eaf53f3 📝 docs(agent-testing): require inline visual evidence (#15750) 2026-06-13 12:28:56 +08:00
YuTengjing c4e4469083 🐛 fix: improve fallback trace error UI (#15746) 2026-06-13 12:18:56 +08:00
Arvin Xu 800b534741 🐛 fix(chat): track operation usage in status tray (#15736) 2026-06-13 11:55:39 +08:00
Arvin Xu 03b9d07d0b feat(topic): add selector topic actions (#15744) 2026-06-13 11:53:21 +08:00
Arvin Xu f60d1fe8dd 🐛 fix(codex): reuse Linear inspector for MCP calls (#15738)
* 🐛 fix(codex): reuse Linear inspector for MCP calls

* 🐛 fix(codex): gate generic Linear MCP labels
2026-06-13 11:46:16 +08:00
YuTengjing e5a27dc97c 🐛 fix: handle Kimi code thinking mode (#15725) 2026-06-13 11:21:25 +08:00
Arvin Xu c7e0c83174 ♻️ refactor(agent-runtime): clarify virtual sub-agent naming (#15737) 2026-06-13 11:10:14 +08:00
Arvin Xu ab958a0b98 🐛 fix(chat): compact operation metrics on narrow inputs (#15735)
* 🐛 fix: compact operation metrics on narrow inputs

* 📝 docs: improve agent testing report template
v2.2.4-canary.11
2026-06-13 02:28:38 +08:00
Arvin Xu 5362be4078 ♻️ refactor(agent): split virtual sub-agent entry (#15733) 2026-06-13 02:10:47 +08:00
Arvin Xu 6887930428 🐛 fix: resolve local markdown image assets (#15729)
* 🐛 fix: resolve local markdown image assets

* 🐛 fix: preserve UNC markdown asset paths

* 🔒️ fix: restrict markdown image previews to images

* ♻️ refactor: pass markdown image preview accept directly
2026-06-13 01:55:00 +08:00
Arvin Xu da94942d9c 🐛 fix(portal): scope local file tabs by working directory (#15732) 2026-06-13 01:54:44 +08:00
Arvin Xu a9141c8ade 🐛 fix(page): stabilize agent editor sync (#15730) 2026-06-13 01:36:38 +08:00
R3pl4c3r 8ab5ec5364 🐛 chore(workflow): fix Upstream Sync workflow running error (#15706)
fix(workflow): fix Upstream Sync workflow running error
2026-06-13 01:29:44 +08:00
Arvin Xu 222534dbe1 🐛 fix(agent): block recursive server sub-agents (#15731) 2026-06-13 01:24:41 +08:00
Neko f31c94490d ️ perf(app,database): derive topic activity from messages (#15726) 2026-06-13 00:57:45 +08:00
Rdmclin2 52eaf2702e 🐛 fix: workspace url sync (#15728)
* fix: workspace url sync

* chore: remove billing as personal
2026-06-13 00:15:48 +08:00
YuTengjing ce81ea44bf 🐛 fix: gate inbox unread count by login state (#15724) 2026-06-12 23:32:14 +08:00
Tsuki 29974d3ab9 🐛 fix(mobile): preserve authenticated legacy unregister cleanup (#15723)
Follow-up to #15719 addressing a Codex P2 review note.

After #15719, legacy v1.0.7 clients that only send `deviceId` were
silent-OKed unconditionally. But `publicProcedure` still receives
`ctx.userId` from `createLambdaContext` — and in the *active*
sign-out path (the user is still authenticated when logout fires)
that userId is valid. Skipping the delete in that case orphans the
existing `(userId, deviceId)` row, so `PushChannel.deliver` keeps
fanning notifications out to a signed-out device. Expo's
`DeviceNotRegistered` receipt only fires on uninstall, not on
logout, so the cron worker doesn't catch this either.

Fix: add a Path B fallback — when `ctx.userId` is available, run
the original `(userId, deviceId)` delete. Path A (expoToken pair)
still wins when present; Path C (silent OK) is now reserved for
the case the original PR was actually targeting: a v1.0.7 client
whose session is already gone, which is the source of the 401
storm.

Path matrix:
  expoToken present                  → Path A: precise delete by (expoToken, deviceId)
  no expoToken, ctx.userId present   → Path B: legacy (userId, deviceId) delete
  no expoToken, no session           → Path C: silent OK, cron cleans up

Tests added:
- legacy + valid session → falls back to (userId, deviceId)
- legacy + no session    → silent OK
- expoToken always takes precedence over userId fallback
2026-06-12 21:58:23 +08:00
Tsuki f4c431b028 🐛 fix(mobile): stop pushToken.unregister 401 storm (#15719)
Symptom: app.lobehub.com production logs show ~50+ TRPCError
UNAUTHORIZED traces per second on /trpc/mobile/pushToken.unregister,
starting from the v1.0.7 mobile release. Only `unregister` is hit
— `register` never appears in logs.

Root cause: the v1.0.7 client calls unregister *during* sign-out,
after the session is already invalid in practice (expired OIDC
token / cleared cookie). With authedProcedure gating, every logout
turns into a 401 that the client mistakes for an auth-expired
event and retries → a storm. Inside the client this also creates
a logout → 401 → authExpired.redirect → logout recursion.

Fix: change `unregister` to publicProcedure and authorize by the
(deviceId, expoToken) pair the client received at registration —
holding both is proof of ownership of that row, same trust model
as APNs/FCM unregister. Legacy v1.0.7 clients that only send
deviceId get a silent 200; the stale row is cleaned up by the
existing `process-push-receipts` worker via Expo's
DeviceNotRegistered receipts.

Returning 200 to those legacy calls also breaks the client-side
recursion at the source — the in-the-wild v1.0.7 fleet stops 401
flooding the moment this ships, before users update.

Tests:
- Router (mocked): expoToken path deletes by (expoToken, deviceId);
  no-expoToken path silently succeeds; unauthenticated caller
  succeeds; empty-string fields rejected.
- Model (integration): only the row matching both fields is
  removed; mismatched expoToken is preserved (defense against
  callers who only guess deviceId).

Fixes LOBE-10174
2026-06-12 21:47:19 +08:00
Innei 34fbd9ffd3 feat(document): coalesce autosave history versions into 10-minute windows (#15716)
*  feat(document): coalesce autosave history versions into 10-minute windows

*  feat(document): break autosave history window on new page load session
2026-06-12 20:55:28 +08:00
Arvin Xu 09b5e926bf feat(conversation): add op status tray above chat input (#14737)
*  feat(conversation): add op status tray above chat input

Show elapsed time, total tokens, and total cost while an AI-runtime
operation is running in the current conversation. Lives in the floating
overlay above the chat input alongside QueueTray and TodoProgress,
attaches flush to the input panel below.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* 🐛 fix(conversation): read top-level message.usage in op status tray

Token totals stayed at 0 during regular agent runs because the standard
agent path writes usage to `message.usage` (top-level) while the
heterogeneous executor writes `metadata.usage`. Read both. Also drop the
fragile createdAt window — assistant messages can be created before the
AI_RUNTIME op's startTime, which excluded otherwise-valid rows — and
aggregate across the whole conversation instead.

UI: a little more padding, a pulsing dot to mark the running state, a
tokens label, and a divider between tokens and cost.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

*  feat(conversation): streaming phase, ping dot, and richer metrics in op status tray

- Left side now shows the current streaming phase (thinking / calling tools /
  searching / compressing / generating) derived from the most recent running
  sub-operation; server runtimes surface no sub-ops on the client and fall
  back to 'generating'.
- Pulse dot upgraded to an expanding ping ring animation.
- Zero-valued metrics are hidden entirely (no more '0 tokens / $0').
- Long-running tasks additionally surface turns and tool-call counts next to
  tokens and total cost.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* 💄 style(conversation): polish op status tray display

* 💄 style(conversation): unify op status tray glyph to a single hue

The activity glyph mixed purple and cyan accents into the primary color;
all layers now derive from colorPrimary alone (opacity-only variation).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* 💄 style(conversation): strip glyph halo fill and drop-shadow

The halo's tinted fill plus the drop-shadow rendered as a muddy disc
behind the glyph (worst in light theme). Reduce to a breathing core dot
plus a single rotating dashed orbit, primary hue only.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* 💄 style(conversation): drop dollar prefix and code font in op status tray

The dollar icon already conveys currency, and the code font made the
numbers feel out of place next to the body text.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

*  feat(conversation): show per-message cost next to the token chip

Renders usage.cost beside the token count in the assistant message
footer; hidden in credit mode (credits already express cost) and when
the value is zero/absent.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* 💄 style(conversation): hide per-message cost below $0.20

Cheap messages don't need a cost callout — the chip only surfaces once
the cost is large enough to matter.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* 🐛 fix(conversation): anchor reconnected op timer to real run start, surface steps

- Page-refresh reconnect recreated the gateway operation with
  startTime=Date.now(), resetting the tray timer to 00:00 mid-run.
  Anchor it to the assistant message's createdAt instead.
- Mirror the server's authoritative stepIndex onto op.metadata.stepCount
  at every step_start event, so the steps metric shows for real
  server-side runs (and survives reconnects).
- Drop the tool-call count metric from the tray.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

*  test(conversation): stub updateOperationMetadata in gateway event handler mock store

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-12 18:10:29 +08:00
Innei d3e8e7cb65 🐛 fix(locale): support eager dayjs locale modules (#15711) 2026-06-12 16:57:42 +08:00
Rdmclin2 60bed5782f chore: update i18n (#15712)
chore: update i18n files
2026-06-12 16:21:34 +08:00
Rdmclin2 35b6bc55b8 🐛 fix: workspace error (#15701)
feat: support workspace (page author, copyTo/transferTo, notifications, i18n & fixes)

Squashed 13 commits from fix/workspace-error for clean rebase onto main's submodule base.
2026-06-12 16:08:31 +08:00
Innei 365dd1ff64 ️ perf(build): remove sitemap generation to cut static export time (#15702)
* ️ perf(build): remove sitemap generation to cut static export time

The sitemap accounted for 772 of 827 prerendered pages, each fetching
marketplace data at build time. Static generation drops from 28.2s to
0.3s and total next build from ~59s to ~32s.

* Redirect legacy sitemap URLs to the landing site

* Redirect sitemap index to landing sitemap
2026-06-12 15:17:52 +08:00
Innei 7633c0e83f 🐛 fix(share): always serve desktop bundle for share routes (#15710) 2026-06-12 14:54:18 +08:00
LiJian 87b1f39c0f feat(skill): add delete/remove actions to settings/skill items (#15708)
*  feat: add delete/uninstall actions to settings/skill items

- LobehubSkillItem: show compact `...` dropdown in list mode for connected items with Disconnect action (revokes OAuth)
- KlavisSkillItem: show compact `...` dropdown in list mode for connected/pending servers with Remove action (true delete via removeKlavisServer)
- ConnectorDetail: add Delete button for custom (mcp) connectors; calls deleteConnector + notifies parent via onDelete
- SkillDetail / Page: thread onDelete callback so selecting null after deletion triggers auto-select of next item
- Locales: add tools.klavis.remove / removeConfirm.title / removeConfirm.desc in en-US, zh-CN, and default source

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(skill): gate Klavis remove by canEdit and clear selected after removal

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(skill): show dropdown for all Klavis/Lobehub items in list mode

Previously, the ... button was gated behind `server` (Klavis) and
`isConnected` (LobehubSkill), so disconnected/never-connected items
showed no actions. Remove those guards so the dropdown always renders
in list mode. handleRemove/handleDisconnect now skip the server call
when no server instance exists and instead clear the selected item.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(skill): move delete/uninstall actions from list dropdown to detail panel

- Remove heavy ... dropdown from KlavisSkillItem / LobehubSkillItem list items
- Add danger Uninstall button to builtin-skill detail header (matches ConnectorDetail style)
- Add slim action bar with Uninstall to agent-skill detail panel
- All actions respect canEdit / canCreate permissions with confirmModal gating

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 12:38:22 +08:00
LiJian ca91d2d756 refactor: replace Segmented tabs with SearchBar in ProfileEditor; gate local-system injection (#15593)
* 🐛 fix: activator tool discovery for cloud-sandbox and local-system

- P0: Explicitly inject LocalSystemManifest when device gateway is configured
  (discoverable: isDesktop is always false on server, so it never enters
  the discovery loop. The explicit injection mirrors the canUseDevice guard.)

- P1: Skip CloudSandboxManifest when runtimeMode is not 'cloud'
  (resolveRuntimeMode unifies executionTarget='sandbox' and legacy
  chatConfig.runtimeEnv.runtimeMode paths, so agents with sandbox
  disabled correctly exclude the cloud-sandbox tool.)

Both fixes operate at the manifest-map build stage, consistently affecting
all downstream consumers (activator discovery, availableTools, etc.)

* 🐛 fix: remove cloud-sandbox manifest when runtime is not sandbox

The initial manifest seed via getEnabledPluginManifests includes
defaultToolIds (which contains lobe-cloud-sandbox), so the manifest
was already in toolManifestMap before the allowedBuiltinTools loop's
continue guard. This made lobe-cloud-sandbox activatable even when
sandbox was disabled.

Add a delete right after resolveRuntimeMode to cover both the
manifestMap seed and the allowedBuiltinTools loop in one place.

Co-authored-by: chatgpt-codex-connector[bot]

* ♻️ refactor: replace Segmented tabs with SearchBar in ProfileEditor tool dropdown

- PopoverContent: replace Segmented with SearchBar + internal client-side filtering (same pattern as ChatInput ActionBar)
- AgentTool: remove ~270 lines of duplicated installedTabItems useMemo; pass unified items
- AgentTool: add auto-cleanup for stale plugin identifiers in agent config
2026-06-12 11:18:44 +08:00
Arvin Xu 61586b9377 🐛 fix(agent): persist & deliver image attachments for device/sandbox hetero runs (#15685)
* 🐛 fix(agent): persist file attachments in hetero early-exit user message

The hetero-agent early exit in execAgent created the user message without
the `files` relation, so attachments sent from the SPA gateway path
(executionTarget=device / sandbox) were never linked via messagesFiles and
disappeared once the optimistic client message was replaced by the server
snapshot. Attach the deduped `fileIds` the same way sendMessageInServer
does on the local-mode path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

*  feat(agent): deliver image attachments to device/sandbox hetero runs

Persisting the messagesFiles relation fixed display, but the dispatched
CLI still never saw the image — local mode feeds the persisted imageList
into sendPrompt for vision, while the device/sandbox dispatch protocols
(agent_run_request / sandbox runner) only carried a text prompt.

- resolve attached images into signed URLs in the hetero early exit
  (metadata-only, non-fatal) and carry them through heteroParams
- add imageList to the agent_run_request wire type and dispatchAgentRun
  params (gateway client + server service)
- extract buildHeteroExecStdinPayload into @lobechat/heterogeneous-agents
  so the three dispatch sites (desktop spawnLhHeteroExec, lh connect
  daemon, server sandbox runner) build the same content-block payload:
  systemContext, prompt, then image blocks
- lh hetero exec already coerces image blocks via coerceJsonPrompt and
  normalizeImage (url → base64 for Claude Code, materialized path for
  Codex), so no CLI consumer changes are needed

openclaw/hermes (runHeteroTask) keep text-only prompts — their dispatch
goes through a separate one-shot tool protocol.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* ♻️ refactor(heterogeneous-agents): move exec stdin wire contract to a pure /protocol entry

The server sandbox runner imported `buildHeteroExecStdinPayload` through the
`/spawn` barrel, which (with no `sideEffects` hint) bundles the whole spawn
machinery into the Next.js server chunk. Its `process.cwd()`-rooted dynamic
fs calls then make Vercel's output file tracing glob the entire repo source
tree into every serverless function (+~69 MB each), pushing the 4 largest
functions past the 250 MB uncompressed limit and failing the deployment.

Split the dispatch wire contract (stdin payload builder + content-block
types) into a new pure, isomorphic `/protocol` export and point all three
dispatch sites (server sandbox runner, desktop main, `lh connect` daemon) at
it. `/spawn` re-exports the moved symbols so executor-side callers are
unaffected. Also declare `sideEffects: false` for the package.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 00:02:51 +08:00
Arvin Xu eca449e4e2 feat(skills): agent-testing iteration after first real-world run (#15700)
* 📝 docs(skills): make agent-testing Step 0 an env-setup + auth checklist

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

*  feat(skills): agent-testing probes, GIF evidence, and report-language rule

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 23:52:25 +08:00
renovate[bot] 6c8976b641 Update dependency vitest to v3.2.6 [SECURITY] (#15698)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-11 23:34:38 +08:00
Arvin Xu 60d9d3c3c7 ♻️ refactor(skills): merge local-testing and cli-backend-testing into agent-testing (#15699)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 23:14:45 +08:00
Arvin Xu 2dd4cf7a1d fix(agentDocument): replace getDocuments with listDocuments in useFetchAgentDocuments to avoid over-fetching (#15301)
* fix(agentDocument): listDocuments returns templateId and derived fields

* fix(agentDocument): useFetchAgentDocuments use listDocuments instead of getDocuments

* fix(agentDocument): derive AgentDocumentItem from listDocuments return type

* fix(agentDocument): export AgentDocumentListItem type

* 🐛 fix(agentDocument): align list projections and consumers after rebase onto canary

- listDocumentsForTopic now returns the same projection as listDocuments
  (derived fields + templateId), so the tRPC union no longer collapses
  the inferred client type to the old 8-field shape
- add description/updatedAt to both projections for sidebar consumers
- AgentDocumentsGroup switches getDocuments -> listDocuments (it already
  shared the documentsList SWR key)
- makePendingDocument trimmed to the lean list item shape
- update useFetchAgentDocuments test to the listDocuments behavior

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* 🐛 fix(agentDocument): migrate agentDocumentSkills sync to slim listDocuments

The tool store's skill registry sync shared agentDocumentSWRKeys.documentsList
with the working sidebar and the new useFetchAgentDocuments hook, but still
fetched the full getDocuments payload. Sharing one SWR key across different
payload shapes made the cached result order-dependent: whichever consumer
mounted first decided whether the cache held the heavy full documents or the
slim list items. Migrate the skills sync to listDocuments, whose projection
covers every field mapDocsToSkills reads.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 22:41:24 +08:00
Arvin Xu 575ef1e8ee ♻️ refactor(agent): single-track device-tool injection via execution plan (#15683)
* ♻️ refactor(agent): single-track device-tool injection via execution plan

P3 follow-up to #15669 — downstream layers now consume the resolved
ExecutionPlan instead of re-deriving device capability:

- ExecutionPlan carries the effective `target`; persisted into
  state.metadata.executionPlan via createOperation
- call_llm executor gates buildStepToolDelta's activeDeviceId signal on
  the plan (none/sandbox can never re-inject local-system mid-run)
- AgentToolsEngine consumes the plan's target; redundant rule-level
  canUseDevice checks removed (physical manifest walls remain)
- builtin agent runtime config can now override agencyConfig
  (web-onboarding pins executionTarget=none)
- hetero desktop 'local' selection persists this desktop's deviceId so
  opening the agent from web dispatches to the same machine via gateway
- 'local' vs 'device' stay distinct user choices even for the same
  machine: gateway dispatch streams progress to all clients (mobile),
  IPC is faster but desktop-session-only — guarded by a regression test

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* 🐛 fix(agent): enforce device access policy on hetero dispatch

resolveDeviceAccessPolicy now runs BEFORE the hetero early exit and feeds
canUseDevice into the hetero execution plan: a denied sender (external
bot user) degrades local/device-bound CLI hetero runs to the cloud
sandbox instead of dispatching to the owner's machine, and requestedDeviceId
cannot bypass the policy. Remote hetero agents (openclaw/hermes) are
device-only with no sandbox fallback, so denied senders are refused
outright.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* 💄 style(agent): fix interface field order in RuntimeSelectionContext

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 22:39:11 +08:00
YuTengjing ba6976c063 🐛 fix: pause input completion after errors (#15692) v0.0.0-nightly.pr15693.16240 2026-06-11 22:05:45 +08:00
Innei bfdfd3bca3 🐛 fix(desktop): adjust mac fullscreen titlebar spacing (#15693) 2026-06-11 22:02:48 +08:00
YuTengjing f6c23e3654 🐛 fix(agent-runtime): persist assistant reasoning to DB (#15690) 2026-06-11 21:05:23 +08:00
Arvin Xu 813d756b9c 🐛 fix(editor-canvas): re-check editor init state before subscribing (#15686)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 20:42:28 +08:00
renovate[bot] 671bc26e0d Update opentelemetry-js-contrib monorepo (#13582)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-11 20:41:48 +08:00
renovate[bot] 309c25cb44 Update dependency code-inspector-plugin to v1.3.6 (#14612)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-11 20:41:40 +08:00
Arvin Xu a810bf3dcd 🐛 fix(agent-runtime): always persist assistant reasoning to DB (#15687)
* 🐛 fix(agent-runtime): always persist assistant reasoning to DB

PR #13494 gated message reasoning persistence behind preserveThinking
(agent chatConfig + model extendParams / qwen|zhipu fallback). That gate
is only meant to control whether reasoning is replayed into the next LLM
payload — applying it to the DB write dropped thinking content for every
non-qwen/zhipu reasoning model in server-side agent mode: reasoning
streamed live via stream_end but vanished after refresh.

Restore unconditional reasoning persistence in messageModel.update and
keep the preserveThinking gate only for state.messages payload replay.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* 💄 style(i18n): localize callSubAgent tool labels

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 20:41:29 +08:00
Arvin Xu 7d6be512b8 🐛 fix(model-runtime): align tool-calling fallback tests & surface missing tool call as error (#15691)
*  test(model-runtime): align tool-calling fallback tests with new return shape

#15680 changed generateObject's tool-calling fallback to return the parsed
schema object (same shape as the json_schema path) instead of an array of
tool calls, and reworked its error handling, but left the pre-existing
"tool calling fallback" block in index.test.ts asserting the old behavior,
breaking CI on canary:

- result is now the parsed object, not [{ name, arguments }]
- the no-tool-call path returns undefined via debug log without console.error
- the parse-failure path logs the single matched tool call, not the array

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* 🐛 fix(model-runtime): surface missing tool call in generateObject fallback as error

tool_choice forces the structured-output function, so a response without a
tool call means the provider misbehaved. #15680 routed this branch to a
debug-namespace log that is invisible in production, leaving callers with
an unexplained undefined. Log it via console.error with the response
message as context, matching the parse-failure branch.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 20:40:12 +08:00
LiJian 1130f7df32 feat(devices): add browser device pairing flow (#15678)
*  feat: add browser device pairing flow to /settings/devices

- Add "Via Browser" tab to ConnectDeviceModal with pairing code display and input
- Add "Register this browser as a device" callout card above DeviceList
- Support ?pair=<code> URL param to auto-open browser pairing modal with pre-filled code
- Improve DeviceList empty state with method cards (Desktop + CLI)
- Ship en-US and zh-CN i18n keys for all new browser/sync strings

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* 🔨 fix(devices): fix lint warnings — import sort order and empty catch block

* fix(devices): add pair API route and invalidate device list cache

- Create /api/devices/pair POST handler that authenticates the user via
  Better Auth session, validates the code against the user's registered
  devices via DeviceModel.findByDeviceId, and returns JSON.
- Replace the setListKey/key-prop re-mount trick with
  lambdaQuery.useUtils().device.listDevices.invalidate() so the tRPC
  React Query cache is properly busted after a successful pair (fixes
  staleTime: 30s preventing the new device from appearing).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* ♻️ refactor(devices): drop browser pairing, fix modal close, redesign UI

- Remove the "Via Browser" pairing flow entirely: browser tab in
  ConnectDeviceModal, the "register this browser" callout card, the
  ?pair=<code> deep-link, and the /api/devices/pair stub route. Only the
  real Desktop and CLI connection methods remain.
- Fix the modal that couldn't be closed: @lobehub/ui Modal closes via
  onCancel (antd), not onClose — the X button was a no-op.
- Redesign the connect modal (segmented tabs, numbered steps, command
  blocks with copy, security footer) and the empty state (onboarding
  hero with Desktop/CLI options + capability cards).
- Clean up browser/sync i18n keys; add capabilities + footer keys for
  en-US and zh-CN.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* 💄 fix(devices): apply card radius — cssVar.borderRadius already has unit

The radius tokens (cssVar.borderRadius / borderRadiusLG) already include
their unit, so the trailing `px` produced `var(--…)px`, which browsers
drop — leaving the cards with sharp corners. Drop the `px` so the cards
pick up the same rounded radius as the appearance settings FormGroup.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 19:50:28 +08:00
Arvin Xu e20496e444 🐛 fix(codex): persist model metadata and file diffs (#15672)
* 🐛 fix(codex): persist model metadata

* 🐛 fix(codex): show file change diffs
2026-06-11 19:15:45 +08:00
Innei dbc8d76c8d feat(desktop): restore cloud desktop builds (#15666) 2026-06-11 19:14:26 +08:00