[pull] main from lobehub:main - #495
Open
pull[bot] wants to merge 5745 commits into
Open
Conversation
…on wide layouts (#17211) * 💄 style(chat): float conversation header over the message stream on wide layouts Codex-style dual-mode header for the agent conversation page, switched by a CSS container query (agent-chat-layout, declared on the chat column): - narrow (<1200px column): solid in-flow bar with a bottom border - wide (>=1200px): the header floats above the full-bleed scrolling stream (absolute / transparent / no border), the 960px reading column stays centered, and the title/action pills keep an opaque backing + subtle shadow so content scrolling underneath stays readable - pointer-events layering: pills stay clickable while the transparent middle of the strip clicks through to the content below - top clearance uses a headerSlot spacer row inside the virtualized list (virtua does not support scroller padding-top) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 🐛 fix(chat): preserve message indices when the header slot row is present The headerSlot spacer prepends one synthetic row to the VList, shifting every virtua row index off the message index. Establish a single contract: all index-based APIs exposed by VirtualizedList (registered store scroll methods, activeIndex) and the hooks that talk to virtua directly work in message index space, translated at the virtua boundary: - registered getItemOffset / getItemSize / scrollToIndex add the offset, so spacer measurement and minimap jumps land on the right rows - getTotalCount excludes the leading header row (same index space as scrollToIndex), keeping scrollToBottom on the true last row - findItemIndex-derived activeIndex subtracts the offset (header row clamps to the first message), keeping the minimap highlight aligned - useTopicScrollPersist restores to headerOffset + last message - the send pin scrolls to headerOffset + user message index Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…age polish (#17250) * ✨ feat(verify): acceptance visibility field and page polish - add acceptances.visibility (personal defaults public, workspace private) with migration/backfill and setVisibility mutation - fix page shrinking under AppTheme's centered flex root so the ledger hugs the viewport edge - open round reports as the full verify run view in a drawer instead of raw markdown - make ledger round cards fully clickable and add per-group collapse footers - restructure the header into identity / verdict / provenance lines with a linked PR chip Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * ✨ feat(verify): public acceptance pages and a verify-style list sidebar - getBundle becomes a public procedure gated by the aggregate's visibility (public → anyone with the id; private → owner / workspace members; denial is a 404), with run origin redacted for visitors - /acceptance/(.*) joins the middleware public routes and the desktop-only bundle paths, matching /verify/:id - new AcceptanceWorkspace master-detail: an acceptance list panel (subject titles resolved server-side) sharing the verify workspace's components and panel preferences, plus an empty-detail route Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 💄 style(verify): headerless round-report drawer The drawer's default header duplicated the report's own hero title; noHeader lets the hero be the header, with a floating close over it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * ⏪ revert(verify): drop the acceptance visibility field, keep public reads Deferred by product decision: the per-aggregate visibility override lands next week. getBundle keeps the verify-report model — the id in the URL is the read capability, with origin still redacted for visitors. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 🐛 fix(verify): open acceptance links in the chat portal on desktop Acceptance links in a conversation navigated the whole app away from the chat while verify links opened in the portal. Acceptance gets the same portal view (copy-link/open-external header, ledger collapsed in the narrow embed), and the checklist header now wraps instead of crushing vertical in narrow containers. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 💄 style(verify): fused comparison cards, sidebar search and list-detail fixes - shared EvidenceComparisonCard: seamless halves, flattened media, caption band (label ?? description) — and the acceptance union renders pairs again - acceptance list panel gets the verify-style always-on search (client filter over the full loaded set) - PR chip hover steps the whole text up one level instead of a link-blue recolor - ingest derives a report verdict from cases when summary.verdict is absent and warns on a missing title, so runs can't list as a permanent ?/untitled Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 💄 style(verify): make the PR chip hover a clear step to the primary text color The previous hover only stepped the title tertiary→secondary (two grays, imperceptible). Lift the whole chip — number, title, icon — to the primary text color at once, still overriding the global link-blue. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* ✨ feat(verify): open the run scenario contract beyond coding - verifyRunScenarios/VerifyRunScenario: coding | writing | research | generic - VerifyRunContext becomes a per-scenario union (VerifyWritingScope / VerifyResearchScope / VerifyGenericScope alongside VerifyCodingScope) - server createRun/updateRun validate context by its sibling scenario: coding keeps strict surface canonicalization, other scenarios store their scope as an open bag so new scenarios need no server redeploy - lh verify ingest-report stops hard-coding scenario=coding: result.json `scenario` passes through (unknown values hard-error) and non-coding reports carry result.json `context` as the scenario's own scope - viewers narrow coding-only chips (branch/commit/PR) behind the scenario gate instead of assuming every context is a coding scope Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 🐛 fix(cli): keep ingest-report pullRequest in scope for text output The coding-branch refactor block-scoped `pullRequest`, but the non-json success output still prints it after the run is created — every plain `lh verify ingest-report <dir>` crashed with a ReferenceError post-ingest. Hoist the declaration next to `context` (restoring it in the --json payload too) and cover the text output path with a regression test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* ✨ feat: add OidcClientModel and oauthApp tRPC router for developer OAuth apps
Add a userId-scoped OidcClientModel with create/list/findById/update/setEnabled/delete
(delete cascades dependent oidc token rows in a transaction) and an oauthApp lambda
router that never exposes clientSecret. Clients get an lca_-prefixed id and fixed
device-flow config.
* ✨ feat: enforce disabled OIDC clients and surface clientId in trpc context
- adapter find('Client') returns undefined for disabled rows (treat as not found)
- stamp oidc_clients.last_used_at fire-and-forget on AccessToken/DeviceCode upsert for lca_ clients
- AuthContext gains oidcClientId populated from validated OIDC JWT client_id
* ✨ feat: add OAuth Apps settings UI
Add a settings tab for managing user-created OAuth Device Flow clients,
gated by isDevMode next to the API Key tab on desktop and mobile.
- ProTable list with logo, copyable Client ID, Device Flow type, timestamps,
enabled switch and delete
- Create modal (name required, description, logo via AvatarUpload)
- Detail drawer with editable name/description/logo, Client ID copy,
enabled toggle, delete confirm and an OAuthAppStats business slot
- Wire lambdaClient.oauthApp.* CRUD, componentMap (+ desktop twin) and enum
- Add auth-namespace i18n keys with hand-written en-US and zh-CN previews
* ✨ feat: third-party developer identity and risk notice on OAuth consent
Show developer line, a warning-tone risk notice, and an optional privacy
policy link on the consent and device-confirm pages for non-first-party
OAuth clients. Developer name is resolved server-side from the client
owner (display name or username), exposing name only. Device-confirm
fetches this metadata from a new /oidc/client-metadata endpoint keyed by
client id. First-party clients render unchanged.
* 🔒 fix(oidc): require auth for client-metadata route
* 🌐 i18n: add oauthApp.stats.* keys for OAuth app usage panel
* 🐛 fix: refresh OAuth app drawer state and cap developer app inputs
* 🐛 fix(oidc): omit null client metadata fields so user-created clients pass schema validation
* ♻️ refactor: switch OAuth apps settings from master-detail to sub-route navigation
* 🐛 fix(oidc): align OAuth apps with user-scoped schema
* 🐛 fix(oidc): scope OAuth apps by workspace
* 🐛 fix: expose OAuth apps in workspace settings
* 🐛 fix: avoid auth route prefix collisions
* ✨ feat: gate OAuth apps UI behind Labs
* 🐛 fix(home): route all result briefs to the daily brief section Splitting on the parent task's runtime status proved fragile: a paused or completed recurring task flipped its whole unresolved report history back into the needs-you pile. Result briefs are completion reports — reading them is enough, so they are news unconditionally. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * ✨ feat(home): add mark-all-read to the daily brief section News briefs only ever got read one by one, so unresolved reports piled up in the capped home feed. A hover action on the section header now bulk- resolves them with a neutral 'read' action — deliberately bypassing the approve path so clearing reports can never complete their tasks. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 🌐 style(i18n): fill markAllRead translations for remaining locales Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* 👷 build: add work registry tables * ♻️ refactor: require work tool identifiers * ♻️ refactor: simplify work version agent attribution * 🐛 fix: add work visibility scope * 👷 build: regenerate work registry migration * ♻️ refactor: replace works.rootOperationId with immutable origin provenance works.rootOperationId was a latest-wins single-value slice of an N:M relation (an edit from another conversation stole the summary card from the conversation that created the Work). Replace it with immutable origin columns (originTopicId/originThreadId/originAgentId) stamped once at identity-row insert, powering upcoming "works created in this topic / by this agent" filters. Query/model changes live in the feature PR.
#17267) * ✨ feat(model-runtime): forward-compatible Kimi K3 model detection * ✨ feat(moonshot): adopt official Kimi K3 API contract and add model card * 💄 style(moonshot): disable server-fixed sampling params for kimi-k3 * 🐛 fix(opencodeCodingPlan): ignore disabled thinking for native-thinking Kimi models
* 💄 style: update i18n * ✅ test: drop stale provider footer assertions left by footer removal
…onversations (#16289) * 🐛 fix(group): include groupId in client message-key reads for group conversations Several client selectors/actions built the messagesMap / operationsByContext key from `activeAgentId` + `activeTopicId` only, omitting `groupId` (and `threadId`). In a group conversation messages and operations are stored under the `group_<groupId>_<topicId>` key, so these reads landed on an empty main-scope bucket and returned nothing. Symptoms: - Topic title generation summarized an empty message set → the model emitted a degenerate "空对话标题" title for group topics (buildRunLifecycle read the conversation with a groupId-less key). - dbMessage / operation / sendMessage-loading|error selectors returned empty for groups, so per-context operation tracking, cancel and clear-error in group chats silently no-op'd. Fix: read with the full conversation context (groupId + threadId), matching the write side (`operationsByContext` is keyed by `messageMapKey(context)`) and the canonical `currentDisplayChatKey`. - buildRunLifecycle: `messageMapKey(context)` instead of `{ agentId, topicId }` - dbMessage `currentDbChatKey`, operation `getCurrentContextOperations`, agentRun `isCurrentSendMessageLoading` / `isCurrentSendMessageError`, conversationControl `cancelSendMessageInServer` / `clearSendMessageError`: add `groupId` + `threadId` Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 📝 docs(agent-testing): add E32/E33 living-log entries E32: driving heteroIngest/heteroFinish directly needs a real OIDC token (hetero-operation JWT signed with the server's JWKS_KEY), plus bun's posix_spawn ENOENT message shape. E33: keep the electron-dev.sh launcher shell alive in process-reaping runners. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…ish leg (#17283) 🐛 fix(hetero): keep status-guide error body through the remote finish leg Remote CC runs relay API failures (529 overloaded / rate limit) as an in-stream error event the adapter already classifies into the structured status-guide shape (agentType + code), which the server persists correctly. But the CLI finish leg kept only the flattened message string and re-derived the error via the process-only classifier (cli_not_found / auth_required), producing a body-less { message } that flushFinalState then wrote over the structured error — demoting the client from the dedicated guide card to the generic error alert. - CLI: capture the terminal error event's structured payload and forward it verbatim as the finish error body - Server: flushFinalState no longer downgrades a persisted status-guide error with a body-less finish error (protects older sandbox CLIs) - Shared isHeteroStatusGuideErrorData predicate in @lobechat/heterogeneous-agents Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…#17263) * ✨ feat: workspace-scoped API keys with RBAC & workspace auth data deletion Squashed from 6 commits: - fix: workspace apikey rbac and workspace scope - feat: support workspace auth delete data - fix: apikey creator display and messenger back to lobe - fix: api keys - chore: optimize dropdown menus - chore: update i18n files Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 🐛 fix: project topic row owner userId in TopicModel.query for client ownership filters Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 🐛 fix: gate owner select-all batch delete behind workspace acknowledge modal & drop stale provider footer test - BatchActionsDropdown: workspace owners deleting a select-all query hit the server's workspace-wide delete (restrictToCreator=false); show the workspace-wide label and the elevated WorkspaceDeleteAllModal, mirroring the header trash button (Codex P1). - The provider roadmap footer was removed in #17217 but the workspace provider test still asserted it renders; update the stale test (canary CI is red on the same test). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 🐛 fix: bind workspace API keys on the lambda TRPC surface Mirror the OpenAPI resolveWorkspaceId contract in createLambdaContext: a personal key is rejected when X-Workspace-Id is present, and a workspace key is pinned to its own workspace (mismatched header rejected, workspace applied even without the header). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 🐛 fix: enforce workspace API key entitlement on lambda auth & seed RBAC roles at workspace creation - createLambdaContext: apply the same canUseWorkspaceApiKeys availability gate as the OpenAPI workspace middleware before accepting a workspace-scoped key (Codex P1). - WorkspaceModel.create: seed the built-in RBAC roles and grant the creator workspace_owner inside the creation transaction, matching the documented assignWorkspaceRoleToUser contract; widen seed helpers to accept transactions. - OpenAPI workspace middleware: fall back to the loaded membership role for the API-key owner check so pre-seeding workspaces are not rejected (Codex P2). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 🐛 fix: re-check workspace API-key issuer owner status on lambda auth Workspace API keys are owner-only: createLambdaContext now verifies the issuer still holds owner status (RBAC role with membership fallback via the new shared hasWorkspaceOwnerAccess helper) before accepting a workspace-scoped key, matching the OpenAPI workspace middleware. A demoted or removed owner's key stops authenticating. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 🌐 chore: refill locales after rebase onto canary Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* ✨ feat(acceptance): per-check user review with feedback loop - user-level accept/reject on each acceptance check (dual check icon: verifier verdict + user confirmation; gray circle = awaiting user) - reject-with-comment per item, incl. circled-region comments drawn on evidence screenshots; feedback renders under the check's evidence - consumed feedback (older rounds) folds into the iteration history - group-level accept-all button - header rework: origin agent/topic line; branch/commit/PR chips moved into the latest-report summary card - acceptances.check_reviews jsonb + reviewChecks trpc + bundle overlay - CLI acceptance view: USER column + user-feedback section; agent-testing skill reads acceptance state + user feedback before the next round Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 💄 style(acceptance): polish review UI — all-verified receipt & reject modal layout Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * ✨ feat(verify): re-land acceptance visibility as the per-aggregate override Reverts cec3d50 (field parts only): acceptances.visibility with scope defaults (personal→public, workspace→private), setVisibility mutation, and visibility-gated getBundle reads. Folded into this branch's 0122 migration, regenerated per the dev-stage migration flow against canary's 0121 snapshot. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * ✨ feat(verify): per-run report visibility, inheriting the acceptance umbrella verify_runs.visibility mirrors acceptances: scope defaults (personal→public, workspace→private), getReportBundle gates private reads to owner / workspace members (denial = null, no existence leak), setRunVisibility is the per-round override. Attaching a round inherits the aggregate's visibility and acceptance.setVisibility cascades over its chained rounds so a report URL never outlives its umbrella. Folded into this branch's 0122 migration. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * ✅ test(verify): fixture visibility for getReportBundle + private-run gating case The router tests mock verify_runs rows as plain objects, so they never carried the new NOT NULL visibility column and the public-read gate saw undefined → denied. Stamp the fixtures public and cover the new branch: a private run is null for visitors and readable by its owner. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…ed agent connector (#17286) * ✨ feat: show which member authorized each shared agent connector When several members share a workspace agent, the profile showed only that (e.g.) Gmail was attached — not whose account it runs on. Attribute every connector to the member who authorized it: - authorizer = metadata.composio.linkedByUserId ?? userId (no migration) - server: connector.list + listByAgent enrich rows with authorizedByName/ authorizedByAvatar via a lean UserModel.getDisplayInfoByIds batch lookup (mirrors the listAgentBound → getAgentAvatarsByIds precedent) - UI: PluginTag renders an "authorized by X" avatar+tooltip, gated behind a new showAuthor prop; resolves the agent-scoped row over the base row. Both the Agent Tools and Workspace Tools profile sections opt in, only in a workspace (personal mode has a single authorizer — the caller). Tests: authorizer resolution + display map (unit), getDisplayInfoByIds (db), PluginTag author wiring + agent-over-base precedence (component). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * ✨ feat: tell the model when a tool runs on another member's account A non-owner running a shared workspace agent could invoke, say, Gmail without any signal that the results belong to the member who authorized it. Inject a <tool_credential_ownership> block into the run's systemRole listing each borrowed connector and its authorizing member, so the model knows whose data it is reading. - reuses the connectors already resolved for the run (userId + metadata), so no extra query in the hot path - only connectors authorized by someone OTHER than the caller are listed; when the caller owns everything (owner runs own agent) nothing is injected, so there is zero prompt cost in the common case - appended before createOperation consumes systemRole; wrapped in try/catch so attribution never breaks a run Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * 🔒 fix: harden connector provenance against spoofing & prompt injection Two review findings on the provenance work: - linkedByUserId is server-owned (written by the OAuth connect path), but the generic connector create/update accepted free-form metadata — a member could set metadata.composio.linkedByUserId to another user's id and spoof the attribution tag + runtime note (and shift the Composio execution entity). New withTrustedLinkedByUserId forces the field to the trusted value (existing DB row's on update, dropped on create) and is applied in both mutations; all other metadata is preserved. - The ownership note concatenated user-editable connector/member names raw into systemRole, so a crafted name could forge a closing tag and inject system-level instructions. Names are now flattened (newlines collapsed, angle brackets dropped, length capped) before embedding. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * 🌐 chore: fill authorizedBy locale for the connector attribution tag `bun run i18n` needs OPENAI_API_KEY, which isn't available here, so the single new `settingAgent.agentTools.authorizedBy` string was translated by hand across the remaining locales (placeholder {{name}} preserved). Safe to regenerate later with the script. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
🐛 fix: preserve boot reload attempts during error reporting
* 🔖 chore(cli): bump @lobehub/cli to v0.0.44 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 🔖 chore(cli): regenerate man page for v0.0.44 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 📝 docs(agent-testing): group reports by acceptance subject & add per-check fixture tooling - report-init.sh: --subject groups runs under .records/reports/<subject-key>/ with an acceptance.json marker, pre-fills result.json.subject for auto-attach ingest - fixture.mjs: init-check / list / compose reusable per-check fixture assets under .records/fixtures/, composing ingest-ready rounds from check.json templates - SKILL.md & references/report.md: document the grouped layout and inputs-vs-outputs fixture rule - common-mistakes: Case 28 — always publish reports to production, create a prod anchor if the subject only exists locally - probe-mock-patterns: C12 (stale global lh silently orphans ingest), D22 (driving the manual-approval intervention chain in web chat) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…accept, accept undo & loading (#17289) * 💄 style(acceptance): review UX polish — status alignment, hover bulk-accept, accept undo & loading - list glyph: delivered-but-undecided reads as in-progress (blue dashed), never a green all-clear - group bulk-accept moves next to the pass ratio, hover-revealed; folds the group on success - per-check accept shows loading and folds the row; accepted checks gain a "change to reject" undo - origin topic chip fully clickable; origin agent chip gets the hover profile popup - report area on white background; collapse-groups demoted to an ActionIcon - expanded rows drop the hover wash; zero-evidence checks say so explicitly Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 💄 style(acceptance): annotation move/resize, reject draft cache, round filter & closing accept - annotation regions are movable and corner-resizable; rects normalize against the image box itself, fixing skewed readback when the frame outgrows the image - annotation notes become auto-sizing textareas; the whole reject draft (comment + regions) survives refresh via localStorage, cleared on submit - a rejected check's head icon becomes the red send-back mark, replacing the verifier's check - group bottom escape hatch gains its label; zero-evidence note gets a filled background - round filter joins the review-state segments (slice the union by verify round) - the delivery-closing decision bar ships accept-only (owner-gated); whole-delivery reject stays per-check Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 🐛 fix(acceptance): key annotation drafts — identity-matched updates drop frames mid-gesture Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* ✨ feat: add work version registry (LOBE-10820) * 🐛 fix: dedupe Work summaries per root operation instead of globally * 🐛 fix: repair zod v4 record schema, bound rootOperationIds, redact work payloads in stream events * ✅ test: align work summary tests with per-operation event semantics * 🐛 fix: surface a Work summary only on the latest operation touching it A Work touched by multiple rounds was chipped under every round's anchor message. Dedupe summaries globally again so only the last touching round carries the artifact chip. * 💄 style: show per-version cost deltas in work version history cumulativeCost is a per-operation running snapshot, so rendering it raw made version rows look like they should sum to the card total but did not (v3 already contained v2's spend). Diff snapshots within each operation so rows show their own spend and visibly add up to the summary card. * ♻️ refactor: registry-driven work type adapters with changeType/resourceLabel naming - Rename work_versions.role -> change_type and works.resource_identifier -> resource_label across schema, migration 0119, types, and the full read/write chain - Introduce WORK_TYPE_ADAPTERS registry so aggregate queries fan out per registered type (missing entry = compile error) and merge the per-type cost queries into one - Collapse the linear/github twin modules into createSnapshotWorkRegister/createSnapshotWorkAdapter factories - Extract shared dispatchWorkRegistrationIntent into @lobechat/builtin-tools for the server executor and client store - Move WorkSummaryCard into src/features/Work with a WORK_TYPE_DESCRIPTORS registry; split WorksSection into VersionList + WorkVersionHistoryCard * ⚡️ perf: skip work summary assembly on mid-stream message refetches Every tool_end / step_complete refetch and every step_start uiMessages snapshot re-ran the per-type Work summary queries for the whole page. Thread a skipWorks flag through getMessages -> MessageModel.query so mid-stream paths skip the assembly; works settle on the initial page load and the terminal agent_runtime_end refetch. replaceMessages grafts previously rendered works back (preserveWorks) so chips don't flicker mid-run. * ✅ test: rename leftover work version role fields to changeType * ♻️ refactor: slim work snapshots to display metadata and rename source to sourceToolName * ✅ test: adapt remaining work registration tests to sourceToolName and slimmed intent * 🔒 fix: enforce task visibility on Work reads and skip Works on share pages * 🔒 fix: allowlist external Work URLs and align Work write permission scopes * 🐛 fix: harden Work registration (snapshot truncation, rejected-write logging, intent stash drain) * 🐛 fix: persist dormant gateway status from ensure reconcile * ♻️ refactor: drop dead tool-execution context fields and fix misplaced work JSDoc * ♻️ refactor: migrate document Work registration to manifest-driven dispatch * ♻️ refactor: merge linear/github work types into one external type Collapse the per-provider `linear` / `github` Work types into a single `external` type before the registry ships, while the persisted shapes (works.type values, snapshot jsonb keys) are still free to change: - unified ExternalWorkVersionSnapshot / list / summary / event / register types; github's repo/number snapshot fields dropped (no consumers — identifier already encodes owner/repo#number) - one external.ts registers/queries for both providers; skill-result routing becomes a SKILL_TOOL_RESULT_NORMALIZERS registry where `satisfies Record<WorkSkillProvider, …>` turns a whitelisted provider without a normalizer into a compile error - WORK_PROVIDER_RESOURCE_TYPES is the single provider ⇄ resourceType source; the reverse lookup is derived, never hand-written - provider-specific tool-result PARSING (linearToolResult / gh CLI tokenizer) is intentionally untouched — only its output type unifies - WorkGallery keeps per-provider Linear/GitHub tabs, now filtering by provider over the unified type; SWR workspace key switches to the gallery filter key so the two tabs don't share a cache entry; i18n keys unchanged Adding a future provider = WORK_SKILL_PROVIDERS + resource-type map + one normalizer; no new types, DB model, or UI descriptor. Note: dev databases seeded before this commit hold works.type = 'linear'/'github' rows that the queries no longer match; re-seed or ignore (branch has no production data). * ♻️ refactor: lift Work display columns onto works and drop version snapshots Schema redesign from PR review (branch-local tables, no shipped data): - works: progressive-disclosure display columns — title (layer 1), description (120-char preview, layer 2), content (full untruncated text, layer 3; NULL for document Works whose layer 3 is the document itself) — plus identifier/status/url lifted from the per-version snapshot - work_versions.snapshot (jsonb) deleted: versions are a pure audit log; the works row holds the merged current display state, updated under the same FOR UPDATE lock as the currentVersionId bump (patchFields → column- granular patch; absent → full overwrite) - sourceToolIdentifier on both tables: works keeps the creator tool (coalesce write-once), work_versions the per-mutation tool; threaded from the tool payload identifier through both transports, skills stamped DB-side from the provider - id shapes: works prefix work→wk; work_versions text nanoid→uuid (and works.current_version_id retyped to uuid to keep the join operator valid) - works.resource_id now nullable (NULL bypasses the partial unique indexes) - task Works keep status NULL: the live tasks join stays authoritative Migration 0119 regenerated in place. Dev DBs that already applied the old 0119 will journal-skip the new one — reset the dev DB (or drop works/work_versions and re-run migrate) to pick up the new shape. * 🔒 fix: hide private-document Works from other workspace members workOwnership let any workspace member list a document Work even when the backing document was private. Add documentVisibilityGuard (mirroring taskVisibilityGuard): non-registrants must pass an EXISTS check that the backing document is public or their own. Orphaned document Works (backing row hard-deleted) stay visible to the registrant only. * ♻️ refactor: cap works.content at write time and drop document title fallback - content is capped at 65,536 chars (GitHub issue-body limit) in buildWorksDisplaySet — the single choke point every registration path writes the works row through — so an agent-generated multi-MB body can never land on the row that every list/summary query selects - document Works no longer synthesize a filename fallback for a null title at write time: the card already falls through to the identifier at the call site, and the stored title should keep data gaps visible * ✨ feat: record creation conversation provenance on works * ♻️ refactor: rename works provenance columns to sourceTopicId/sourceThreadId * 🐛 fix: relay work registration intents over the agent gateway * 🐛 fix: redact skill work payloads from recorded step events * 💄 style: mirror work file keys to en-US and fix import order * 💚 fix: correct type errors in gateway work relay tests * ⚡️ perf: optimize work registry queries * ⚡️ perf: trim work card query payloads * ♻️ refactor: centralize work registration adapters * ♻️ refactor: store work display snapshots in versions * ♻️ refactor: materialize current work snapshots atomically * ♻️ refactor: require work tool identifiers * ♻️ refactor: simplify work version agent attribution * 🐛 fix: enforce work visibility scope * 👷 build: regenerate work registry migration * 🐛 fix: resolve post-rebase type conflicts * ✅ test: add missing sourceToolIdentifier to registerClientWorkFromIntent fixture * ♻️ refactor: replace works.rootOperationId with immutable origin provenance works.rootOperationId was a latest-wins single-value slice of an N:M relation: an edit from another conversation silently stole the summary card from the conversation that created the Work. Replace it with: - immutable origin columns (originTopicId/originThreadId/originAgentId) stamped once when the Work identity row is inserted, powering upcoming "works created in this topic / by this agent" filters - listSummariesByRootOperations now anchors each Work to the latest version event WITHIN the requested operation set, so foreign edits can no longer unhook a conversation's summary cards * 🔨 chore: align 0121 migration meta with canary after rebase * 💄 style: drop the works list header row and top margin in message works * ✨ feat: add topic-grouped works gallery to resource page
…o run metadata (#17266) * 📝 docs(skills): warn against speculative jsonb metadata columns * ✨ feat(agent-runtime): propagate originating request client ip/ua into run metadata * 📝 docs(skills): add agent-testing living-log entries E32 and C12
* ⚡️ perf(desktop): eliminate quick composer overlay open stall Defer globalShortcut callbacks via setImmediate so await continuations are not stranded on an idle main-process event loop (intermittent 1-4s stall before the overlay opened). Cache + prewarm the macOS screen capture permission status, and add [perf] milestone probes across the overlay open path (main process + renderer). * 🔥 chore(desktop): drop overlay perf probes, keep the fixes
* ✨ feat: add agent bot monitor * 🐛 fix: keep webhook bots alive on keyword flips & allow clearing locked keywords * 🐛 fix: scope monitoring-flip restart to external gateway & permit keyword removals when locked
…17296) * 🐛 fix(device): order device lists by liveness, show last connected Device lists were ordered by `lastSeenAt DESC` alone, and nothing sorted by `online`. Both are wrong in the same direction: - `lastSeenAt` is stamped on register/enroll and never refreshed while a connection is held, so it means "last REGISTERED", not "last alive". A box that reconnects on every boot outranks one holding a month-long session. - The router then concatenated the pools (`[...personal, ...workspace]`, `[...fromDb, ...ghosts]`), so even that order was discarded. Net effect: offline machines sat at the top of the run-target picker — where they render `disabled` — pushing the only pickable machine out of a 240px viewport. Add `sortDevicesByActivity` (types) and apply it at the merge boundary in `listDevices` and `getScopedOnlineDevices`. `online` is a HARD partition, so `lastSeenAt` staleness can never let an offline device outrank an online one; `deviceId` breaks ties so polling can't reshuffle rows under the cursor. Also surface the time inline in the settings row instead of hover-only — it's the answer needed to pick between rows, and hover can't give it for a whole list at once, nor at all on touch. Offline copy says "last connected" rather than "last active" because that is what the column currently holds; it becomes a true last-active once a writer stamps liveness. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * 🐛 fix(device): sort gateway channels newest-first `sortDevicesByActivity` ranks an online device by its freshest channel (`Math.max(channels[].connectedAt)`), but every consumer reads `channels[0]` as the device's current connection — the settings row's "Connected {time}", a ghost row's `lastSeen`, its hostname/platform fallback, and the detail panel's connection list. The gateway promises no channel order, so a multi-channel device could rank by one connection and be labelled with another — the row would sit above its neighbour while showing an older time, reading as a broken sort. Normalise at `deviceGateway.queryDeviceList` — the single entry point both `listDevices` and `getScopedOnlineDevices` pull channels through — rather than at the one display site, so all five `channels[0]` readers inherit the invariant. The comparator keeps its own `Math.max`: it is an exported util in `@lobechat/types` and must hold for any input, not depend on a caller having normalised first. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * 🐛 fix(device): guard indexed access in channel order test `result[0].channels` fails `noUncheckedIndexedAccess` — indexing returns `DeviceAttachment | undefined`, and `channels` is itself optional on that type. Chain both. An undefined on either hop still fails the assertion loudly rather than silently passing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * 🌐 chore(device): translate last-connected copy for remaining locales `devices.lastSeen` changed meaning ("last active" → "last connected") to match what the column actually holds; the other 16 locales still carried the old wording. Hand-translated rather than scripted: `bun run i18n` retranslates every pending entry, which would have pulled unrelated namespaces (e.g. an untranslated `verify.json`) into this PR. Each locale reuses the verb already established by its sibling `devices.channel.connected` — aktiv → verbunden, activité → connexion, 활동 → 연결 — so the two lines read as one register, and keeps its existing `{{time}}` placement (incl. RTL). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* 🐛 fix: allow verifier to read task documents * 🐛 fix: reuse existing agent document binding * 🐛 fix: inject document tool for task verifier * ✅ test: relax PDF loader timeout
…c-compatible providers (#17629)
* 🐛 fix(acceptance): refine check review navigation * 🐛 fix(acceptance): narrow nullable origin metadata
* 💄 style: refine single-file edit summary * 🐛 fix: preserve single-file diff access
…17634) The mobile client (`/trpc/mobile`) calls `notification.list` / `markAsRead` / `unreadCount` to render its Notifications tab, but the `notificationRouter` was only mounted on the lambda router — so every call failed with `No procedure found on path "notification.list"` and the mobile inbox stayed empty even for accounts with inbox history. Mount `notification` on the mobile router. It builds on the same `wsCompatProcedure` base as every other lambda router already exposed here, so workspace/personal scoping carries over unchanged. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
The completion notification was gated on `reason === 'done'`, so runs stopped by a step/cost cap (which still produce a deliverable and are persisted as status='done') never fired a recall — inconsistent with the desktop completion notification, which notifies on any clean (non-abort, non-error) terminal. Move the notify out of the done-only block and guard it with `isSuccessLikeCompletionReason` (done + max_steps + cost_limit); the verify gate stays done-only. Capped runs get the same DB-recovered reply preview. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* ✨ feat(acceptance): render structured verification data * 🐛 fix(acceptance): keep chart labels readable in dark mode * 🐛 fix(acceptance): prevent SOTA labels wrapping * 📝 docs(agent-testing): isolate concurrent browser sessions * 📝 docs(agent-testing): fix isolated session example * 🐛 fix(acceptance): simplify structured evidence presentation * 🐛 fix(acceptance): validate visualizations before ingest
* fix(cli): allow runs to be reopened * fix(cli): preserve external run finalization * fix(eval): support reopening external runs * fix(eval): allow direct external run restart * 🐛 fix(eval): surface external result errors * fix(eval): keep run open while topics are running * fix(eval): keep run open while topics are active
* ✨ feat(desktop): preview workspace HTML files * ♻️ refactor(mime): unify MIME detection via @lobechat/utils/mimeType Fold the ad-hoc extension→MIME maps in desktop, CLI, and device-control into a single buffer-aware resolver. `resolveMimeType(path, buffer)` trusts file-type's magic-byte detection first, then falls back to mime.getType with a text-sniff downgrade so ambiguous extensions like `.ts` (video/mp2t vs TypeScript source) resolve correctly everywhere. * fix: resolve html preview ci failures
…t conversational flow (#17047) * ✨ feat(onboarding): add 7-step onboarding data contract + derivation Bumps CURRENT_ONBOARDING_VERSION/MAX_ONBOARDING_STEPS to support the new 7-step flow, adds OnboardingStep/OnboardingCapabilities types, and a pure steps.ts module for visibility/navigation derivation. needsOnboarding no longer re-prompts finished users on a version bump. * 🐛 fix(onboarding): decouple Classic flow and agent-onboarding version from bumped shared constants MAX_ONBOARDING_STEPS (4→7) and CURRENT_ONBOARDING_VERSION (1→2) were bumped for the new 7-step flow but several overloaded consumers broke: - Classic flow used MAX_ONBOARDING_STEPS as its own last-step id; introduce CLASSIC_ONBOARDING_MAX_STEP=4 and use it in Classic/index.tsx, Common/index.tsx's legacy step remap, the store's legacy goToNextStep stop condition, and the layout's skip-to-classic-end handler. - apps/server's agent-onboarding service used CURRENT_ONBOARDING_VERSION to gate resetting UserAgentOnboarding state; freeze it at a local AGENT_ONBOARDING_VERSION=1 so the version bump doesn't wipe legacy users' agent-onboarding progress. - Removed a stale comment in packages/const/src/user.ts claiming version bumps re-prompt onboarding, which needsOnboarding no longer does. * ✨ feat(onboarding): build web onboarding flow shell + Step 1 Welcome Introduce src/features/Onboarding/Flow with the visible-step-driven flow shell, StepCard chrome, and Welcome step (language + telemetry). Rewire /onboarding to the new flow, drop the classic-jump skip logic from the shared layout in favor of a plain finish-and-navigate skip, and unregister /onboarding/agent and /onboarding/classic from the desktop and mobile routers (old feature/route files untouched for a later removal task). * 🐛 fix(onboarding): mount flow container, fix dangling nav, use BRANDING_NAME Wraps the new onboarding flow page in OnBoardingContainer so the header, skip footer, and callbackUrl stash actually run on mount. Repoints the Footer agent-onboarding CTA away from the removed /onboarding/agent route, and swaps a hardcoded "Lobe AI" literal for BRANDING_NAME in the Welcome step. * ✨ feat(onboarding): implement Step 2 Connect apps with Composio toggles Replaces the ConnectApps placeholder with the real step: Gmail/Notion/X/GitHub toggle rows backed by a useConnectAppToggle hook whose checked state always reflects the live composio store connection status. Adds Notion, X (Twitter), and GitHub to the Composio app catalog (frontend half of the backend contract). * ✨ feat(onboarding): implement Learn your world + Profile steps Adds the frontend contract, service stubs, SWR-polling analysis view, and profile view for onboarding steps 3-4, gated behind the still-off `capabilities.analysis` flag until the backend endpoint ships. * ✨ feat(onboarding): implement Chief Agent step to name and hire the inbox agent Wires the ChiefAgent onboarding step to the existing inbox-agent meta update path (useAgentStore.getState().optimisticUpdateAgentMeta), with inline name editing, a preset/upload avatar grid, and persistence only on "Hire this agent". * 🐛 fix(onboarding): guard chief agent hire against persist failure and stale seed hire() now checks the agent store save status after persisting (and catches a rejecting next()), toasting an error and staying on the step instead of silently advancing when the write fails. The seed effect no longer clobbers a name/avatar the user already edited while the inbox agent meta fetch was still in flight. * ✨ feat(onboarding): implement Messenger + local agents step Wire the messenger capability to the real availablePlatforms source and build the step-6 UI: platform connect rows, a local-agents panel with a desktop download CTA, and a quote banner. Extends StepCard/Banner with an optional bannerContent slot, additive to existing steps. * 🐛 fix(onboarding): latch capabilities and fix Connect flash in Messenger step Latch messenger/composio/analysis/starterTasks capabilities so a transient SWR error (e.g. tab refocus after OAuth) can't eject the user from a visible step, wire isLoading through useMessengerPlatforms so already connected platforms render a skeleton instead of a flashing Connect button, and dedupe buildTelegramDeepLink against the existing Messenger constants export. * ✨ feat(onboarding): add starter tasks step and wire flow analytics Implements Step 7 of the redesigned web onboarding flow behind capabilities.starterTasks (still hidden), plus deferred flow-shell analytics wiring (step viewed/completed, onboarding completed). * 🐛 fix(onboarding): fire step-completed analytics only after mutation succeeds trackOnboardingStepCompleted fired before the awaited setOnboardingStep/finish mutation resolved, so a rejected mutation still recorded step progress. Also add matching error handling to the N=0 starter-tasks submit path. * 🔥 chore(onboarding): remove old agent/classic onboarding UI and routes Deletes the dead conversational-agent and classic-form onboarding flows (src/features/Onboarding/Agent|Classic|Common, their route wrappers, and ModeSwitch) now that /onboarding is fully served by Flow/. Relocates the still-used ServerIcon and Composio OAuth/server-action hooks from the old route-level components into Flow/steps/ConnectApps, and drops the now-orphaned agent-onboarding promo card from the home footer. * 🔥 chore(onboarding): retire agentOnboarding store slice and dead services Removes the agentOnboarding user-store slice and its wiring, drops classic-only goToNextStep/goToPreviousStep/updateDefaultModel actions and the commonStepsCompleted/agentOnboarding-aware needsOnboarding selectors (finishedAt alone is sufficient — legacy finishers mirror it server-side), and deletes the now-unused userService client methods and the onboardingFeedback service. CLASSIC_ONBOARDING_MAX_STEP goes with it. Also fixes resume semantics: useOnboardingFlow now ignores a persisted onboarding.currentStep when its version predates CURRENT_ONBOARDING_VERSION, so a legacy unfinished user restarts at the first visible step instead of landing on a v1-semantics step index. * 🔥 chore(i18n): drop onboarding/common copy owned by the deleted flows Removes agentOnboardingPromo.* (dead footer promo) and the onboarding namespace keys (agent.*, agentPicker.*, modeSelection.*, proSettings.*, responseLanguage.auto/desc/saveFailed/title2/title3, telemetry.agreement/ helpImprove/privacy/terms, username.*, interests.hint/title/title2/title3, top-level title) that were only referenced by the deleted Agent/Classic onboarding flows, across the source locale and all shipped locale files. * 🐛 fix(onboarding): serialize onboarding jsonb writes to prevent clobbering setOnboardingStep and finishOnboarding each whole-object-replace the server-side onboarding jsonb, so a late-landing step write could erase finishedAt written by a concurrent finish. Chain writes through an in-flight promise so they execute in call order, and make finish's optimistic store update land synchronously so a queued step write composes its payload with the already-finished finishedAt. Deleted the dead stepUpdateQueue/isProcessingStepQueue machinery, which had zero callers, in favor of this minimal chain. * 🐛 fix(onboarding): hold resume state until capabilities resolve, unify skip analytics resolveVisibleStep fell back to the last known visible step (ChiefAgent) whenever a persisted step exceeded it, so a persisted Messenger step with the availablePlatforms() fetch still pending let a fast click finish onboarding before Messenger ever rendered. useOnboardingFlow now exposes isResolving, true only while the async capability sources have not settled once (success or error) and the persisted step exceeds the currently known last visible step; the Flow page renders a spinner instead of a step while that holds. The global skip control previously bypassed useOnboardingFlow.finish() and its trackOnboardingCompleted call. finish() now accepts an optional { skipped } marker (additive on OnboardingCompletedPayload) and the container's skip affordance is driven by the flow's shared finish path via a new onSkip prop, so skip and last-step completion share one code path and both emit completion analytics only after the mutation succeeds. 🔥 refactor(onboarding): move the onboarding container into the Flow feature src/features/Onboarding/Flow/index.tsx imported OnBoardingContainer from @/routes/onboarding/_layout, a feature reaching into route code. Moved the container (component + style + test) to src/features/Onboarding/Flow/Container/; src/routes/onboarding/ is now just the thin re-export. * 🐛 fix(onboarding): minor review cleanups - Drop user-content interpolation from onboardingAnalysis/onboardingTasks stub error messages, matching the plain-message sibling stubs. - Remove the unused ChiefAgent style.hint entry. - Fix "Custom your chief agent operator" -> "Customize your chief agent operator" in the default en-US onboarding copy. * ✅ test: preserve provider namespace coverage * ✨ feat(onboarding): flesh out profile, supplement modal and starter tasks with mock data - mock onboardingAnalysis.getProfile and onboardingTasks suggestions until backend lands - redesign supplement modal: about-you textarea, composio app toggles, refine CTA - add play button to starter tasks step and edit icon to tell-us-more - temporarily enable analysis/starterTasks capabilities to expose the mocked steps * 💄 style(onboarding): wire step banner artwork and restore chief agent card design * ✨ feat(onboarding): wire understanding pipeline into Flow steps * ♻️ refactor(onboarding): OSS falls back to Classic, remove 7-step Flow Restore the Classic form onboarding (Telemetry, ResponseLanguage, FullName, Interests, ProSettings, AgentPicker) from canary and render it directly at /onboarding; the 7-step Flow moves to the cloud repo. - Remove src/features/Onboarding/Flow/** and the Flow-specific services (onboardingUnderstanding, onboardingAnalysis, onboardingTasks). - Rewrite the /onboarding route to a Classic-only entry: shared-prefix steps followed by the Classic branch inline, no Agent/Classic branching. - Reconcile with the reworked user onboarding slice: add CLASSIC_ONBOARDING_MAX_STEP, restore goToNextStep/goToPreviousStep and the commonStepsCompleted selector additively; strip the Agent switch/skip footer from the layout. - Restore the Classic i18n keys across all locale mirrors; the new flow.* keys stay for the cloud repo to consume. The store slice rework, types contract, understanding.ts types, SWR keys and analytics increments are kept. Agent conversational onboarding stays removed. * 🐛 fix(onboarding): remap legacy out-of-range classic step on resume * ✨ feat(onboarding): add 16 chief-agent persona copy from LOBE-11583, drop mbti placeholder * 🔥 chore(i18n): drop unused persona personality/speaking-style keys * 📝 docs(agent-testing): record reload-safe mock-state pattern (B4) * 🐛 fix: pass response language to onboarding understanding * ✨ feat(onboarding): expose registered understanding providers to clients * ✨ feat(feature-flags): add onboarding_v2 flag * ✅ test(onboarding): align canary tests with the branch's onboarding version and responseLanguage contract --------- Co-authored-by: Neko Ayaka <neko@ayaka.moe>
* 🐛 fix(agent): enable drag-to-collapse builder panel * 🐛 fix(agent): enable drag-to-collapse working sidebar
* 🎨 style: clarify acceptance detail actions * 🎨 style: elevate acceptance check status * 🎨 style: tighten acceptance detail density * 🐛 fix: support acceptance details on mobile * 🐛 fix: align task acceptance details with canary * 🐛 fix: converge task acceptance after auto repair * 📝 docs: record task acceptance polling probe * 🐛 fix: distinguish task acceptance criteria from results * 🐛 fix: unify task acceptance criteria and results * 💄 style: add focused acceptance review actions * 🐛 fix: isolate task criteria and settle repair chains * 🐛 fix task acceptance persistence races * 🐛 fix task acceptance result convergence * 💄 polish task acceptance creation checks * 💄 refine ungrouped acceptance controls * 💄 unify task acceptance definition heading * 🐛 align task acceptance with current plan * 🐛 preserve task acceptance check history
* 💄 style: hide workspace file tree noise * ♻️ refactor: centralize workspace tree exclusions * ♻️ refactor: move working sidebar into features * 🎨 style: preserve review module formatting * ⚡️ perf: optimize workspace file exclusions
* ✨ feat(acceptance): simplify checklist presentation * 📝 docs(testing): record acceptance proxy fallback * 💄 style(acceptance): refine focused check spacing * ✨ feat(acceptance): add close lifecycle action * 💄 style(acceptance): refine status actions * 🐛 fix(acceptance): hide shared-viewer history controls * 💄 style(acceptance): tune focused check rhythm
#17661) layoutAnimation on TooltipGroup can cause janky layout shifts in the generation topic grid; drop the prop.
# 🚀 LobeHub Release (20260728) **Release Date:** July 28, 2026 **Since v2.2.11:** 92 merged PRs · 17 contributors > This weekly release makes Agent work easier to review and recover, with structured verification, broader model access, clearer completion feedback, and a smoother desktop experience. --- ## ✨ Highlights - **Acceptance review flow** — Open focused checks, review structured metrics and charts, and accept or reject delivery from one unified surface. (#17566, #17631, #17633, #17650) - **Chat image generation** — Let chat models discover image models, inspect parameters, start generation, and follow generation status through a built-in tool. (#15332) - **More model access** — Use a ChatGPT subscription through device authorization, run Claude Opus 5, and select the latest Gemini Flash models. (#17527, #17582, #17608, #17433) - **Agent work visibility** — Turn generated files into durable Works, summarize edited files, and notify users when long Agent runs finish. (#17423, #17331) - **Desktop file preview** — Preview local HTML work with its relative assets while keeping file access inside the approved project root. (#17545) --- ## 🏗️ Agents, Tasks, and Verification - Unified Task criteria, check results, focused review comments, and accept or reject actions across desktop and mobile. (#17631) - Added versioned structured verification data for metric comparisons, curves, scatter plots, heatmaps, SOTA tables, and grouped bar charts while retaining the raw evidence. (#17633) - Kept shorter Acceptance checklists flat, grouped only larger lists, and protected owner-only run history in shared views. (#17650) - Kept scheduled runs visible in active conversations and triggered recall for success-like completion states, including auto-repair outcomes. (#17473, #17613) - Preserved human-intervention message ancestry after server-runtime rehydration so submitted or skipped responses stay attached to the requesting assistant. (#17628) - Synchronized Task editor state and grouped retries, and restored image paste in the browser runtime. (#17585, #17644) --- ## 🤖 Models and Generation - Added ChatGPT subscription authentication through the Codex OAuth device flow and a provider-scoped Responses runtime. (#17527) - Added Claude Opus 5 runtime and model-card support, including adaptive-thinking defaults and summarized thinking display. (#17582, #17608, #17620) - Sanitized replayed reasoning for Anthropic-compatible providers so missing text and foreign signatures do not break cross-model conversations. (#17629) - Added Gemini 3.6 Flash and Gemini 3.5 Flash-Lite, preserved Google image resolution when aspect ratio is automatic, and corrected range-priced GPT model costs. (#17433, #16677, #16991) - Added a built-in chat image-generation tool that reuses the existing model discovery, generation, and status pipeline. (#15332) --- ## 🖥️ Desktop and User Experience - Added Preview and Source modes for local HTML files, including project-scoped asset resolution for CSS, JavaScript, images, fonts, audio, and video. (#17545) - Moved the Working Sidebar behind a shared feature boundary and filtered OS metadata, dependency directories, caches, generated artifacts, and editor backups from project files. (#17646) - Rendered gitignored project files in the Agent file browser and retained desktop browser webviews in the renderer. (#17517, #17513) - Unified development tools in a bottom DevDock and restored React DevTools through a standalone desktop bridge. (#17499, #17602) - Preserved Windows `PATH` order when locating Claude Code and Codex, and simplified terminal controls and Topic context menus. (#17381, #17609, #17642) --- ## 🔒 Security and Reliability - **Security:** Kept local HTML preview resources inside the approved project root after symlink resolution. (#17545) - **Reliability:** Restored correct provider error handling for Ollama and woke registered-only gateway connections during sync. (#17344, #17536) - **Reliability:** Removed layout animation jank from the generation Topic grid while preserving tooltip behavior. (#17661) - **Reliability:** Restored CI translations and English fallback, guarded calculator null values, and made tool-name compression fully disable when configured with a zero limit. (#17605, #17588, #17530) --- ## 👥 Contributors Huge thanks to **17 contributors** who shipped **92 merged PRs** this cycle. @smbslt3 · @H-TTTTT · @Solaris-star · @YOYO-do · @alienslime · @jiuyige · @sxjeru · @AmAzing129 · @Innei · @tjx666 · @arvinxx · @rdmclin2 · @nekomeowww · @rivertwilight · @sudongyuer · @ONLY-yours · @cy948 --- **Full Changelog**: v2.2.11...release/weekly-20260728
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )