[pull] main from lobehub:main - #105
Open
pull[bot] wants to merge 6439 commits into
Open
Conversation
Add a dedicated `goals` table so a goal is an independent target entity instead of a JSONB marker on `tasks.config.goal`. - goals table owns its definition (title / requirement), budget (max_rounds / max_total_cost) and lifecycle state, decoupled from task.status - execution carrier is an optional polymorphic link (subject_type / subject_id), so a goal can back a task-driven /goal flow today, a conversation-declared goal later, or stand alone — no hard dependency on tasks - add goalStatuses / goalSubjectTypes consts exported via `@lobechat/const/goal` - register goals id namespace (goal_ prefix) and schema export - add drizzle migration 0141 + snapshot Co-authored-by: Arvin Xu <arvin.x@lobehub.com>
* ✨ feat(expertise): add data schema * ♻️ refactor(expertise): tighten lesson section types * ♻️ refactor(expertise): use UUIDs for internal records * ♻️ refactor(expertise): require domain owners * 🐛 fix(expertise): enforce domain consistency * ♻️ refactor(expertise): regenerate migration after rebase
* 🐛 fix: preserve session on provider key errors * 🐛 fix: silence expected provider key errors
fix(docker): include swc helpers runtime
#18338) Replace the Home-list dump in the agent/project header popover with a compact searchable picker, and forward Popover trigger props so the select can open.
* ✨ feat(expertise): add model and ingestion backend * ♻️ refactor: harden expertise generation and ingestion * ✅ test: cover expertise scopes and workspace isolation
…18367) * 🐛 fix(acceptance): pin review predictions to a vision-capable model The predictor inherited the verifier's chat model via resolveVerifyModelConfig, which in production resolved to deepseek-v4-pro — a text-only model. The channel stripped the evidence screenshots ("Unsupported Image"), so the model accepted every check on the prompt's missing-evidence rule at floor confidence, and no proposal card ever surfaced. Pin the predictor to gemini-3.6-flash@google — the model the offline baseline was scored on, vision-capable and ~13x cheaper than kimi-k3. The pin also keeps agreement stats comparable across acceptances instead of varying with whichever verifier each run used. A regression test asserts the pinned model carries vision: true in model-bank. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * ♻️ refactor(acceptance): source the review-predict model from business-const Move the pinned model/provider values into @lobechat/business-const next to DEFAULT_ONBOARDING_MODEL, so the cloud build overrides them by swapping the stub package instead of patching the verify service. The vision guard test now looks the pin up in LOBE_DEFAULT_MODEL_LIST by provider, so it keeps holding whatever provider the constants point at. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…ning page (#18195) * ✨ feat(expertise): add the self-evolving surface end to end Model / router / page for the SCLPT expertise layer, behind a Labs toggle. - ExpertiseModel: binding resolution (agent + workspace), latest snapshot per domain via DISTINCT ON, hit tiers computed server-side (relative cut, not an absolute threshold — one domain practised 47 times and another twice can't share one). - expertise router: maturity is refused, not faked, when the fit is pending, low-confidence, or its τ hit the search ceiling. 6 of 9 backtests pinned at the boundary, and the earlier implementation reported all of them as normal percentages. - /agent/:aid/self-learning: domain rail + learning curve (bars = rules learned that round, projection drawn only when the fit is credible), layer coverage with blank layers kept visible, and the rule base ordered by hits. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * 📝 docs(acceptance): record the shared-Postgres migration skip The managed acceptance Postgres is shared by every worktree, and drizzle decides what to apply from journal timestamps. A sibling worktree that applied its own same-numbered migration minutes later makes yours get skipped in silence while the command still prints "migration pass" — found while verifying #18195, where all eight expertise tables were missing after a green migrate. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * 💄 style(expertise): rebuild self-evolving around the curve, not a rail The rail made picking an expertise the first thing you do, when the first thing you want is what state they are all in. Both levels now follow the prototypes. L0 — every expertise's curve on one chart, normalized to maturity so a 3-rule domain and a 34-rule one are comparable. The shape IS the conclusion, so colour encodes shape (flat / rising / declining / stuck) rather than rank; a legend that names four shapes while the colours track a leaderboard is worse than no colour. Above it, one sentence of judgement; below it, insights and a list whose bars are cumulative — a bar that grows to the top means done, with no "shrinking is good" translation needed. L1 — the full fit panel on its own route (deep links work): observed solid vs projected dashed, today's divider, the 90% target, and four cards where r² sits next to maturity on purpose. The pinned-τ backtests all had beautiful r² — what they fit beautifully was the straight stretch, so "fits well" and "extrapolates credibly" have to be readable as two different things. Also fixes the count the last acceptance round caught: practice count came from listRuns' length, so a 60-run domain read 50 in the detail and 60 in the list. It is its own COUNT now. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * 💄 style(expertise): give the empty state the shared illustrated Empty Acceptance feedback on round 1: two lines of centred text read as a rendering hole rather than a state. Uses @lobehub/ui Empty with the feature's own icon, the same shape every other empty surface in the app uses. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * 💄 style(expertise): draw the half of the fit chart nobody had seen The extrapolation, the 90% target and "N more practices" only render when the fit is credible AND the domain is still short of 90%. Neither seeded domain met both, so the chart's whole right-hand side had never been exercised — it looked finished while its main visual was untested. Also wires the bars to hadHumanInLoop, which the schema has carried since day one and nothing read: blue is the practices you were in. That contrast is itself a finding — the rounds where someone was in the conversation are the rounds it learned fastest — and a single-colour bar cannot say it. Subhead now names the curve shape ("estimated ceiling 97, and the curve is still climbing") rather than stopping at the number. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * ✨ feat(expertise): close the review round — two write paths and the copy Round 3 review, nine items. The two that needed backend: - The empty state now creates an expertise. The form is mostly one field — what counts as practice — because that filter is the only executable thing a expertise has before it has learned anything, and it is what stops it learning from everything. A filter a human wrote IS a chosen anchor, so it lands practisable rather than in a second "confirm the direction" step. - "这里缺少可行的 action?" was right: the screen said pick a direction and offered nowhere to pick. Candidates now render with a button that applies the chosen one's layers, canon and filter. The rejected candidates stay in anchorCandidates — six months on someone will ask what the other branch would have looked like. The rest: breadcrumb gains the 自进化 level; the projection note moves under the chart title; formulas and statistics terms become sentences (P∞(1−e^(−n/τ)) → "projected at the current pace", 学习率 1/τ → 学习速度 with "one cycle per 60 practices"); layer bars become fixed-width right-aligned tracks so the module reads as the gap between layers rather than a wall per row; an uncomputable fit hides its three empty metric cards instead of showing a row of dashes; 算不出 → 暂不确定 in the list. Two things the new write paths exposed: a never-practised expertise was drawn as an empty grid with five "run 1" ticks, and was tagged 练了没学到 — which is a failing grade for something that has not started. Both now have their own state. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * ✨ feat(expertise): make the path visible, and the snapshot readable Round 4 review. Two of the notes were about the whole thing rather than any one screen, and those drove the work: **"Missing a tracing of the full flow — from first seeing it, through accumulating data, to checking state."** Every screen stood on its own but nothing said how they connect, so a first-time visitor sees curves and has no idea what to do to make them move. A three-step strip now sits under the headline — pick a direction / let it do the work / read where it stands — with the count of expertises that have reached each step. It is progress and navigation at once: stuck on step two means the direction is set but nobody is using it for real work. **"Need something like a word cloud or domain snapshot — the counts read flat, no sense of the whole."** They do read flat: 73 and 1 look the same weight in a right-aligned column, you have to read line by line to compare. The coverage block now scales type size and fill with rule density, so the skew IS the picture. Zero layers keep a dashed outline — the gap is the part most worth seeing. The rest, item by item: creation collapses to one sentence with the name parsed out server-side (the sentence itself stays the filter, unrewritten — rewriting a user's criterion rewrites what the expertise will learn); empty-state and "算不出" copy turn positive ("这里还没有积累", "还需时间积累"); rule bars adopt the same fixed-width right-aligned track as the layers so both columns share one ruler; the projection note drops its "observed a full cycle" tail; anchor-pending gains a where-the-data-comes-from block; a lone expertise renders as a full card instead of one thin row under a lot of white space. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * ✨ feat(expertise): simplify the self-learning review flow * ♻️ refactor: require expertise direction upfront * ✨ feat: ingest topic context into expertise * ♻️ refactor: defer expertise ingestion to review * ✨ feat: add expertise rules detail view * ✨ feat: add expertise lesson drilldown * 📝 docs: audit self-evolving UX surfaces * 💄 style: refine self-evolving experience * 🐛 fix: complete expertise ingestion flow * 💄 style: clarify expertise learning hierarchy * 🧪 test: support non-streaming Responses stub * 🐛 fix: complete automatic expertise generation * 💄 style: refine expertise lesson evidence layout * 💄 style: align expertise detail metadata * 💄 style: tighten expertise modal spacing * ✨ feat: ingest historical topics into expertise * 💄 style: compact expertise detail layouts * 💄 style: align expertise detail fields * 🐛 fix: align expertise UI with generated domains * 🐛 fix: chart cumulative expertise learning --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…#18348) * ✨ feat(database): add resource transfer requests schema and migration * ♻️ refactor(database): move transfer enums to @lobechat/types and drop schema-level enum typing * 📝 docs(skill): add schema conventions (no pg enums for growing domains, no const exports from schemas) to db-migrations * 🐛 fix(database): preserve transfer audit rows when actors are deleted (set null instead of cascade) * 🐛 fix(database): exclude null-recipient rows from the pending-transfer unique index * 📝 docs(skill): scope the schema-constant rule to domain literals in new/modified schemas
# 🚀 LobeHub Release (20260816) **Release Date:** August 16, 2026 **Since v2.2.13:** 363 merged PRs · 21 contributors > This cycle gives longer-horizon work a durable home: Projects and Goals land as first-class containers for agent work, seven new CLI coding agents join the heterogeneous runtime, a Local Sandbox executes on your machine, and the platform opens up through a generated OpenAPI spec and SDK. --- ## ✨ Highlights - **Seven new CLI coding agents** — Cursor, CodeBuddy, Qoder, Kimi Code, Pi, TRAE, and Grok Build (ACP) join the heterogeneous runtime, plus a Codex app-server lab. (#18229, #18219, #17965, #18228, #17899, #18292, #18254, #18275) - **Local Sandbox** — A local execution environment for devices, with a real working directory instead of a refusal. (#18143, #18180) - **Public API & SDK** — `openapi.yml` generated from routes, a new `@lobehub/sdk` package, expanded v1 endpoints, and scoped API keys. (#17944, #17980, #18141, #18029) - **Home customization** — A Customize modal with Minimal / Balanced / Full presets, a day-paged daily brief, and a task-shaped task mode with scheduled tasks. (#17912, #17948, #17958, #18173) - **Desktop split views** — Split tab views, a tab strip reworked for many-tab use, and a faster cold start. (#18004, #17809, #17811) --- ## 🏗️ Core Agent & Architecture ### Projects & Goals(Alpha) - Project schema, backend and CLI, workspaces with conversation PoC, and an identifier column. (#17996, #18006, #18020, #18034) - Goal creation split from task creation with an explanatory empty state; goals get their own table and AI-generated acceptance criteria. (#18047, #18335, #18265) - Goal launch requires confirmation even in auto-run mode. (#18111) ### Agents & Groups - Group member permissions with personal model choice on shared builtins. (#18122) - Async agent transfer and copy, with history backfill and intact membership lifecycle. (#17997, #18030, #18082, #18126) - Sub-agents follow the parent model by default, with thinking controls. (#17938) - Agent quota gets a usage calendar and burnout projection. (#18117) ### Context & Memory - Graph runtime context is injected continuously; container message tokens count toward the context budget. (#17761, #17839) - Every memory tool call renders a dedicated card; extraction prompts align with their schemas. (#17891, #17988) - Opt-in automatic topic summary workflow. (#17796, #18171) --- ## 📱 Platforms & Integrations ### Heterogeneous CLI Agents - New runtimes: Cursor CLI with model selection, CodeBuddy, Qoder with reasoning effort, Kimi Code, Pi, TRAE, and Grok Build over ACP; Codex app-server session lifecycle completes as a lab. (#18229, #18244, #18219, #17965, #18160, #18228, #17899, #18292, #18254, #17907, #18275) - The model selector is driven by a capability table, with local CLI descriptors centralized as a single source of truth. (#18214, #17979) - Windows support hardened: CLI spawning, agents behind unknown shims and stale PATH. (#18095, #18220) - A heterogeneous error taxonomy classifies terminal errors; cloud auth failures surface clearly. (#17887, #18040) ### Desktop - Split tab views, a tab strip reworked for many-tab use, and pinned tabs that travel. (#18004, #17809, #17857) - Boot straight into the last active workspace; cold-start critical path reduced and the local database prewarmed after navigation. (#17946, #17811, #18218) - Chromium zoom presets and update downgrades. (#17679, #18012) ### Messaging & Bots - `/mode` command switches bot conversation mode; recent same-channel history is injected. (#18197, #16608) - Proactive messenger push with per-channel notification settings. (#17791) - Discord completes deferred forwarded interactions. (#18169) ### Models - Gemini 3.7 Flash, GLM-5.3 with always-on thinking, Grok 4.6 reasoning effort, and MiniMax-H3 video with official v2 API. (#18289, #18290, #18301, #18225, #17827) - Audio lands in multimodal understanding with input cost estimation; Cerebras and Groq gain advanced reasoning parameters. (#17904, #17949, #16469) --- ## 🖥️ User Experience - Home: mine/team scope and author chips on recent topics, open goals in the rail, and one-page dashboard scrolling with a persistent recents cache. (#17908, #18121, #17836) - Chat: web voice messages, editable opening questions, keyboard-driven AskUserQuestion with select-to-submit, and a reachable, effective error-card retry. (#17744, #18003, #17903, #18080) - Agent identity: an avatar studio with one-click brand-style generation, profile artwork with style presets, and personal names with a dice-roll composer. (#18113, #17929, #17986, #17853, #17894) - Workspace agents organize with labels and a shared sidebar; the sidebar header becomes an identity switcher. (#17848, #18338) - Resource library: path-based category routes with a Files category, origin filtering, and restored document scrolling. (#18083, #18170, #18345) - Onboarding: Notion and X understanding sources, streamed generation progress, and confirmed starter tasks that run immediately. (#18110, #18118, #18105, #18224) --- ## 🔧 Tooling & API - OpenAPI spec generated from routes via hono-openapi, shipped as the generated `@lobehub/sdk`. (#17944, #17980) - v1 API adds api-keys, evals, mcp-servers, and usage endpoints. (#18141) - API key scopes, with workspace keys scoped to member permissions. (#18029, #18136) - Jupyter notebook (.ipynb) upload with token-efficient markdown conversion. (#17855) - CI gates bundle size for web dist and desktop asar. (#17970) - Agent tracing visualizes context composition. (#18114) --- ## 🔒 Security & Reliability - **Security:** custom provider base URLs are validated (#18223); restricted knowledge bases are soft-hidden from members (#18282); deleting a connector unlinks remote accounts (#18270); auth cookies support custom prefixes and subdomain sharing (#18358, #18200). - **Reliability:** blocking Redis XREAD runs on a dedicated connection (#17876); file parse cache writes are serialized (#17919); repeated network-error toasts collapse into one (#17873); runs no longer strand in `verifying` (#18164); sessions survive provider key errors (#18343). - **Performance:** PDF parsing drops a 25MB native dependency (#17858); agent page render cost is cut across sidebars, composer, and topic list (#17991); recent-topic previews are batched instead of per-topic subqueries (#17928). --- ## 👥 Contributors Huge thanks to **21 contributors** who shipped **363 merged PRs** this cycle. @sxjeru · @Cyber-Yichen · @northword · @smbslt3 · @hardy-one · @orangeboyChen · @nightcityblade · @Max-Reisinger · @Mark-star-dot · @ImSingee · @BittuBarnwal7479 · @arvinxx · @Innei · @AmAzing129 · @tjx666 · @rdmclin2 · @neko · @lijian · @sudongyuer · @rivertwilight · @cy948 --- **Full Changelog**: v2.2.13...release/weekly-20260816
…lock layout (#18375) * 🐛 fix(home): exclude live schedules from recent tasks and align the block layout The recent-tasks block now requests the list with automated: false, so tasks that still fire on their own (cron schedules, heartbeats) appear only in the scheduled block below instead of printing twice on one page. The automation filter joins the cache key and the shared-list scope reset, and refreshTaskList invalidates task:list variants by key root. Layout polish on the same block: the task blocks share a 12px inline inset so row hover pills stay inside the column, and row timestamps get a fixed 56px right-aligned slot so times and avatars form straight columns across both sections. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 🐛 fix(home): hide completed tasks from the recent block Finished work is history for the Tasks page, not part of "what is going on", so the recent block now narrows the request to the non-completed statuses. The include-list is derived from the canonical TASK_STATUSES set rather than hand-listed, so a status added later shows up on Home by default. The status filter joins the automation filter in one trailing cache-key slot and in the shared-list scope reset. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 💄 fix(home): show the animated running mark on live task rows A task that is executing right now wears the shared RunningGlyph ring instead of the static status dot — the same liveness signal running topics and the home rail cards already use — in the recent-tasks block and the sidebar recents. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…desktop (#18379) * ✨ feat(billboard): open web onboarding for resetOnboarding action on desktop * ✨ feat(billboard): restrict desktop resetOnboarding action to official cloud * ♻️ refactor(billboard): resolve action availability via guard pipeline * 🐛 fix(billboard): coerce isSyncActive selector to strict boolean
…livery-checker (#18376) * ♻️ refactor(verify): unify acceptance criterion UI and remove lobe-delivery-checker - Add shared CriterionList / CriterionRow / CriterionRequiredChip and a single CriterionEditor + openCriterionEditModal under src/features/Verify/CriterionList - Migrate the /goal intervention card, CreateGoalModal, TaskVerifyConfig, PendingAcceptanceCheckList, TaskAcceptance and GoalDetailPage to the shared row/editor, deleting the two duplicated criterion edit modals - Unify the required chip to a blue info tag labelled 必选 (verify:criterion.*) and drop the divergent 必要/必需/必选 key trio across chat/plugin namespaces - Delete the unused builtin-tool-lobe-delivery-checker package with its server runtime, registry entries, i18n keys and the orphaned createPlanFromCriteria Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 📝 docs(acceptance): note stale-cache fingerprint of a cross-wired browser session Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * ♻️ refactor(verify): apply acceptance review feedback on criterion editing - Drop the pending-status icon and C{seq} anchor from goal-creation draft rows — those belong to the post-creation check list, not authoring - Remove TaskVerifyConfig's edit mode (SortableList reorder, side drawer, Done button): every row now edits itself through the shared criterion modal, matching the goal-creation interaction; regenerate moves into the header overflow and add/save-as-template become always-visible footer actions - Simplify the criterion edit modal title — no C{seq} interpolation Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 📝 docs(acceptance): record ingest-side identifier/internal-id gap in probe patterns Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * ♻️ refactor(verify): apply round-2 acceptance review feedback - Keep the C{seq} anchor on goal-creation draft rows; only the pending status circle stays out of authoring - Drop the at-rest delete button from task criterion rows — removal lives inside the editor modal - Move save-as-template from the footer into the header overflow menu - Show the verifier tag and required chip on goal-detail check rows Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * ♻️ refactor(verify): fold task criterion row edit and delete into a per-row overflow Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* 🐛 fix(chat): restore embedded conversation toolbar * 🐛 fix(chat): bind embedded toolbar topic state
* ✨ feat(chat): add realtime voice dictation * 💄 style(chat): refine dictation listening control * 💄 style(chat): round active dictation control * 💄 style(chat): apply circular dictation radius * 💄 style(chat): animate dictation listening halo * ⚡️ perf: reduce dictation connection latency * 🐛 fix(chat): preserve dictation control focus * 🐛 fix: support keyboard dictation controls
* 💄 style(ui): align loading skeletons with page layouts * 🐛 fix(ui): satisfy profile skeleton flex types
…#18390) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…to the goals table (#18374) * ♻️ refactor(goal): migrate goal implementation from task.config.goal to the goals table Make the new `goals` table (#18335) the single source of truth for goal identity, budget, requirement and lifecycle, replacing the JSONB marker on `tasks.config.goal`. - add GoalModel (create / findBySubject / listBySubjects / updateStatus with startedAt/completedAt stamping / deleteBySubject) + tests - write paths: TaskService.createTask accepts a `goal` input and creates the bound goals row; the createGoal tool runtime (server + client executor) and the CreateGoalModal both go through it — the config-merge race between the goal marker and verify config is gone, and the unused originTopicId is dropped (task.context.origin.topicId already records it) - read paths: settle / goalLoop / acceptanceService / taskLifecycle / buildTaskPrompt / deleteGoal resolve the goal via GoalModel.findBySubject; TaskModel.getGoalConfig and TaskGoalConfig are removed; the hasGoal list filters become an EXISTS on goals - status machine: goals.status is now server-written — running on run start (planInstantiation) and loop rounds, verifying/review mirrored from the acceptance lifecycle, review on converged verify, paused on exhausted budget or reject-without-budget, failed on errored verify, achieved on accept, canceled when the carrier task is canceled - reads attach the goal entity to task list/detail responses (groupList / getTaskDetail / ProjectModel.listTasks); the client consumes task.goal instead of casting config JSONB, and goalPresentation prefers goals.status over the task-status heuristic Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 🐛 fix(goal): stop reading the planned acceptance phase as verifying The verify plan is instantiated and confirmed at RUN START, so the acceptance lifecycle sits in `planned` for the whole executing round. Mapping that phase to `verifying` (both in the server-side goal-status mirror and in the client presentation tiers) showed 验证中 for a goal that was actually executing its round — caught by the E2E acceptance run on a live goal task. - acceptanceService.mirrorGoalStatus: drop the planned → verifying mirror; the goal stays `running` until verification actually runs - goalPresentation.acceptanceStatusKey: let `planned` fall through to the goal-entity status tier instead of rendering 验证中 - regression tests on both layers Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 📝 docs(acceptance): record the Goals page entry + Labs toggle probe recipe Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 💄 fix(goal): apply acceptance review feedback on goal status visuals Two circled-region review items from the acceptance round: - the create-goal modal's criterion rows no longer show the dashed check-status circle — verification has not started at creation time, so the state glyph carried no meaning there - a running goal now shows the same spinning ring as running task topics (shared RunningGlyph) instead of a static dot, via a new GoalStatusGlyph used by the list row, card view and detail header Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 🐛 fix(verify): address codex review on the shared criterion components - CriterionEditor: an existing criterion's judging rule lives in a linked document this editor neither loads nor can update (updateCriterion has no instruction field) — show a read-only note instead of an editable blank box that silently discards input - CriterionRow: ignore Enter/Space bubbling from nested action controls so keyboard activation of an edit/delete button no longer also opens the row Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 🐛 fix(goal): address codex review on goal-row lifecycle integrity Two of the three codex findings are real integrity gaps in the FK-less goals ↔ tasks link; the third (legacy config.goal backfill) is a deliberate product decision documented on the PR. - TaskService.createTask: compensate a failed goal insert by deleting the just-created task. Deliberately compensation instead of a transaction — TaskModel.create's identifier-conflict retry continues after a 23505, which an enclosing transaction would abort. Without this, a transient goal-insert failure left a ghost task that never lists on goal surfaces and stacks on retry. - TaskModel.delete / deleteAll: sweep the bound goals rows inside the same transaction. deleteAll (the task.clearAll path) previously never swept at all, permanently orphaning every cleared goal; single delete swept in a second non-atomic statement. - regression tests for the compensation path (service) and the bulk sweep with cross-user scoping (model, real DB) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * ✅ test(taskLifecycle): mock GoalModel in the onTopicComplete suite onTopicComplete now asks the goals table whether the completed task carries a goal (goal-loop rounds suppress the per-topic brief). The suite passes a bare `{}` as the db, so the un-mocked GoalModel blew up on `db.query.goals` in CI (Test Server shard 2/2). Mock it like VerifyRunModel — default: no goal. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* 🧪 test: bootstrap local device gateway * 🐛 fix: preserve goal acceptance contracts * ♻️ refactor: keep goal criteria domain neutral * 🐛 fix: collect hetero acceptance evidence server-side * 🐛 fix: detect hetero evidence by provider * 🐛 fix: require self-contained goal evidence * 📝 docs: bound long-running health probes * 🐛 fix: pin installable UI dependency * 🐛 fix: pin installable UI in desktop workspace * ⬆️ chore: unpin repaired UI dependency * 🐛 fix: charge stale work before recovery --------- Co-authored-by: Arvin Xu <arvin.x@lobehub.com>
…#18694) * ✨ feat(desktop): gzip renderer OTA CAS and keep r0 plus last-2 deltas Tree-diff with zstd --patch-from instead of re-downloading the full renderer, gzip the original CAS objects, and generate deltas from the packaged r0 tree plus the two most recent patch versions. * ♻️ refactor(desktop): simplify renderer OTA lineage * 🐛 fix(ci): publish renderer base after r0
Co-authored-by: Arvin Xu <arvin.x@lobehub.com>
…approval mode (#18705) * fix: task verify config pannel * 🐛 fix: stop stale multi-tab settings writes reverting tool approval mode * 🐛 fix: make tool intervention merge atomic in a single SQL statement * 🐛 fix: route builtin-tool uninstall writes through an atomic tool-column patch * 🐛 fix: keep aborted settings columns pending and pin uninstall writes to the captured workspace
…me (#18672) * 💄 style(acceptance): make the AI review round always report its outcome The predict button's poll waited for proposal CARDS, but an agreeing verdict renders none — so on a clean delivery the button span the full two-minute timeout and then said nothing, indistinguishable from the feature being broken (which it recently was, making the two literally untellable apart). The mixed-decision case was broken in the other direction: already-decided checks counted toward the exit threshold, ending the poll before the batch finished. The bundle now carries predictionStatus per check — the fact that the attempt finished (judged/skipped/errored), separate from the owner-only card gating which is unchanged. The poll exits when no pending check lacks a status, and the round always ends in a toast: N flagged / reviewed-and-agreed / could-not-judge / still-running. Zero cards becomes a stated result instead of silence. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 🐛 fix(acceptance): reset the previous batch before re-requesting AI review Found while planning the acceptance run: the predictor upserts on completion, so a second click left the previous batch's rows in place until each replacement landed — and a poll that waits for 'every check has a recorded attempt' saw that condition met on its first tick, ending with a stale summary before one new judgement had finished. predictReviews now clears the current reviewer's unanswered rows before dispatch (adjudicated rows are labels and stay), so a missing row means 'not judged yet' for the whole batch. The bundle also reads only the current reviewer's rows: after the model pin changed, a stale row from the old model would otherwise satisfy the poll the moment the new one was cleared. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 💄 style(acceptance): tone the AI-review toasts by outcome A green tick on 'could not form an opinion' read as the review having passed — the exact ambiguity the toast exists to remove. Inconclusive is now a warning; nothing-pending and still-running are info; only real verdicts are success. Also records the local verification recipe for the predictor (pinned Gemini vs the OpenAI-shaped stub, SSRF fetch-back of evidence images, no pending row state) in the acceptance probe living log. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Arvin Xu <arvin.x@lobehub.com>
…nt stacks (#18712) - Add a desktop "Font" settings group with an Interface Font picker backed by the system font list, alongside the monospace picker moved out of "Terminal". - Apply the monospace preference to antd's fontFamilyCode so it drives code blocks everywhere, not only the built-in terminal. - Build the app font stack in src/const/font.ts and insert the UI language's own CJK block (JP / KR / TC) ahead of the SC families, so Japanese, Korean and Traditional Chinese no longer render Han glyphs with Simplified fonts.
…18719) * 💄 style: add workspace waitlist landing link copy and official url Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 🌐 style: add auto-translated locales for waitlist landing link Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 💄 style: add new-tab hint copy for waitlist landing link (a11y) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…18680) * ✨ feat(gateway): let a gateway pull the connections it should hold A gateway keeps its registry in memory, so a restart leaves it holding nothing while the database still knows what should exist. Recovering that by having the server push on demand needs a lock, a cooldown and a reconciliation protocol, all to answer one question — and the side doing the asking still cannot see whether the connections came back. Answer it as a read instead: the gateway asks for its list and builds it itself, so the side that establishes the connections is the side that can see the result. Retrying a read is free. The response body is what the reconcile would have pushed, built by the same function, so a connection does not depend on who established it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * 🐛 fix(gateway): do not hand over a connection its previous host still holds Routing a platform to a host does not make its connections safe to build there. Right after the routing changes, the host that owned them a moment ago is still polling — hand one over before that host is drained and every message is delivered twice until a later reconcile catches up. The reconcile already enforces this. The pull path was bypassing it and answering from routing alone, so a gateway restarting mid-migration would rebuild the whole fleet alongside the old one. Withheld entries make the answer partial, so the caller keeps asking. It runs out of attempts long before a hand-off completes, which is correct: finishing one is the reconcile's job, not this call's. An unreadable host counts as drained, the same trade-off the reconcile documents — a steady-state deployment has nothing on the wrong host, so blocking recovery on an unrelated outage costs more than it saves. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * 🐛 fix(gateway): never move a platform to a host that cannot serve it Routing a platform to a host is currently taken on faith. Point it at one that cannot serve that platform and the result is not a no-op — it is an outage: the stale pass drains the connections off the host that was serving them, and the connect meant to replace them is rejected, so they end up on neither. Gateways already describe themselves. Ask, and refuse the move when the destination says it does not serve that platform: leave the connections running where they are and let the misrouting be corrected. Only an explicit declaration counts. A gateway that does not describe itself makes no claim, and silence must not be read as refusal — one of ours has no such endpoint, and treating it as "serves nothing" would make rollback impossible, which is far worse than the case being prevented. Also names the platform entries that match nothing, whose only symptom is otherwise that the change quietly does not happen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * 🔒 fix(gateway): let a caller pull only the host that rebuilds this way `host` was caller-controlled while every gateway authenticates with the same service token, so the token could not say which gateway was asking. A token that leaked out of one of them could name the other and read its credentials — which that token could not do before this endpoint existed, since the admin surface returns ids and states, never credentials. Only one host rebuilds by pulling; the other recovers from its own durable registry. Asking for that one's slice can only be a caller reaching for credentials that are not its own, so refuse it. Keeping exactly one pull-capable host is what makes "who is asking" answerable without per-host credentials; a second one would need them first. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * 🐛 fix(gateway): a half-seen host does not prove it released anything The cross-host check treated any snapshot it got back as authoritative, but a stats-only one — registered ids failed, live stats did not — omits dormant registrations. An id missing from it says nothing about whether that host still holds it, so a restart mid-migration could take over a connection the other gateway is only sleeping on, and deliver twice when it wakes. Withhold what such a view does show, and mark the answer partial so the caller keeps asking rather than settling for it. Absence is only absence when the view was complete; finishing a hand-off stays the reconcile's job. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * 🔒 fix(gateway): derive the pulling host from its credential, not the request The endpoint that hands back a host's credentials was authenticated with the token every gateway shares, so the server could not tell which one was asking and had to trust a `host` field the caller wrote. Blocking one value narrowed that to "read your own", not "read at all" — the credentials are on the side that legitimately pulls, and naming it was allowed. Give the pulling host its own credential. One credential, one host, so presenting it IS the claim of who is asking, and the request no longer names anything. A second pull-capable host gets its own, never a share. Keeping the shared token here was the wrong call and the reason was wrong too: it is not a two-party secret. It is written into every WeChat connect payload as `webhookToken` and persisted with the connection config, so it lives across the fleet's storage. Manipulating connections with it is the exposure already accepted; reading every credential in one request is not. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * 🐛 fix(gateway): hand over only what a complete peer view proves released Marking the answer incomplete did not protect anything. The caller applies every config it receives and only then asks again, so a flag lands after the duplicate it was meant to prevent — the connections were still handed over. A dormant registration missing from a stats-only snapshot could start here while still running on the host that owns it. Absence is evidence only when the view was complete. A snapshot that could not be fetched and one that omits dormant registrations are the same claim: nothing. Withhold in both cases. That is stricter than the reconcile, deliberately. The reconcile owns hand-offs and has the machinery for them — drain before connect, per-round caps, ids tracked as they are released. This call has none of that; it is an optimisation over the reconcile, so when it cannot be done safely the right move is not to do it. The test asserted the flag rather than the withholding, which is why the gap survived the previous round. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * 🔒 fix(gateway): do not hand a host credentials for a platform it cannot serve Routing a platform to a host does not mean it can run it. The reconcile already refuses to move such a platform, but the pull handed its configs over anyway and left the gateway to reject each one — functionally contained, but it arms nothing and exposes the credentials for nothing. The asymmetry was also the trap: a reader of the reconcile would take the guard as enforced, while the path that actually returns credentials skipped it. That is the same shape as the cross-host check this endpoint was missing before. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
✨ feat(artifact): package local sites for hosted publishing
* ✨ feat: consolidate home promo surfaces * ✅ test: stabilize home banner queue in CI
…18703) The product surface is the Acceptance domain: every route is /acceptance, and what lived under features/Verify was either the acceptance page itself or one of its sub-objects — a round's report, the in-chat round card, the criteria editor. 'Verify' no longer named anything of its own, and the page sat at features/Verify/Acceptance, one level deeper than its siblings. New layout, grouped by sub-object instead of nesting Acceptance/Acceptance: - Viewer/ the acceptance page atoms (was Verify/Acceptance) - Workspace/ the acceptance list panel (was Verify/Acceptance/Workspace) + useReportPanelExpand - Report/ ReportViewer and the evidence/visualization renderers (was Verify/components) - Run/ RunResult and CheckerDock, the in-chat round card - CriterionList/, hooks, utils, routeMeta unchanged at the root Removes the dead VerifyWorkspace / ReportListPanel / EmptyDetail trio (zero consumers since AcceptanceWorkspace replaced it). Pure move otherwise: git detects 90 renames; imports rewritten across src, apps/workbench and packages, plus the path literals in the workbench stub tests and two skill docs. Co-authored-by: Arvin Xu <arvin.x@lobehub.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…th its cost (#18735) * 💄 style(quota-calendar): lead each day with its cost and flatten the window list The weekly window list repeated "Last observed window" on every past row and labelled every meter "Capacity used", so five rows of chrome carried one row of information. Each window is now a single line — span, meter, percentage, spend — with only the live window named. The day cells inverted the reading order: a coding agent's calendar is scanned for money, so the cost now leads and the token count backs it up. Token counts also stepped from M straight past a billion, printing "3136M" where the rest of the product would say "3.1B". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * 💄 style(quota-calendar): keep a lower-bound day cost inside its cell Leading a day cell with its cost put "at least $836" where a seventh of the panel had to hold it, and the label truncated to "at least $…". The cell now wears the bound as a suffix — "$836+" — which also keeps every amount in the grid starting on the same glyph. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * 📝 docs: record how to reach and seed the quota usage calendar Verifying the calendar cost three dead ends worth writing down: the composer only mounts the quota panel for a local-execution hetero agent, the ledger (not the window rows) is what both the day cells and the per-window totals read, and the modal resolves the account by the live CLI identity's externalAccountId. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * 💄 style(quota-calendar): make the window list one card of divided rows Review feedback on the first round: single-line rows do not each need their own fill, and the spelled-out "at least" inside a dense row is noise. The rows now sit flush in the panel card separated by hairlines, and every amount in the modal body wears the lower bound as a "+" suffix. The words move to the row's tooltip, which the session grid already had and the list did not. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * 📝 docs: note that the live CLI reading overwrites a seeded current window Opening the quota panel ingests the machine's real reading into the same account row, so the current window's percentage is never the seeded one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Arvin Xu <arvin.x@lobehub.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* ✨ feat(database): persist heterogeneous interventions * feat(database): generalize agent intervention approvals * 🐛 fix(database): supersede partial approval batches atomically * 🐛 fix(database): fence custom intervention execution retries * 🐛 fix(database): harden intervention recovery boundaries * 🐛 fix(database): merge plugin state atomically
* ✨ feat(agent): support durable heterogeneous interventions * 🔒 fix(agent): keep review tokens out of query URLs * ✨ feat(agent): align approval workflows with web * ✅ test(agent): align approval runtime expectations * ✅ test(agent): align client approval expectations * 🐛 fix(agent): expose live activity batch terminality * 🐛 fix(agent): harden durable approval recovery * 🐛 fix(agent): reconcile approval claim state * ✅ test(agent): type durable approval fixture
…base-ui (#18729) The antd-based wrappers are deprecated since @lobehub/ui@5.33.0. This moves every call site to the base-ui subpath. Beyond the import path, the migration required: - ActionIcon now renders a native <button> instead of a div: dropped the hardcoded 'nativeButton: false' in ActionDropdown's trigger props (it overrode the library's own inference, so Base UI applied role/aria-disabled to a real button), and retyped the dictation control refs to HTMLButtonElement - Avatar is no longer antd's: replaced src/icon with avatar, dropped gap (no equivalent) - Tag is no longer antd's: dropped bordered={false}, which antd v6 already ignored whenever variant was set — and the wrapper always set it - prop types (ActionIconProps, AvatarProps) now come from the base-ui subpath, since the legacy ones carry antd props and a div ref - seven files that still imported Button from @lobehub/ui or antd are migrated too, since touching them surfaced the existing no-restricted-imports error: variant=filled -> type=fill, variant=outlined + color=default -> type=default Verified: type-check clean, 503 tests pass across ChatInput/NavPanel/User, and the migrated surfaces render with no Base UI warnings.
* ✨ feat(heterogeneous-agent): support Grok provider bindings (#18737) * ✨ feat(db): add workspace document comment schema (#18726) * ✨ feat(db): add workspace document comment schema * ♻️ refactor(db): use UUIDs for document comments * 🐛 fix(db): sync comments during document transfers * 🐛 fix(db): harden document comment transfers * 🔨 chore(db): regenerate document comment migration * 🐛 fix: align chat output cost estimate ratio (#18748) * ♻️ refactor(desktop): migrate renderer OTA to V2 packs (#18745) * ♻️ refactor(desktop): migrate renderer OTA to V2 packs * ⚡️ perf(desktop): decode renderer packs asynchronously * 💄 style(toast): align toast radius and offsets with desktop layout container (#18755) * 👷 ci(desktop): read the overlay repository from a variable instead of hardcoding (#18759) Claude-Session: https://claude.ai/code/session_01TQcoZnDo12NGCxWZDJpciZ * 👷 ci(share): add PR-time verify workflow for the share micro app (#18757) * 👷 ci(share): add PR-time verify workflow for the share micro app Claude-Session: https://claude.ai/code/session_01TQcoZnDo12NGCxWZDJpciZ * 👷 ci(share): build same-repo PR previews with the cloud overlay Claude-Session: https://claude.ai/code/session_01TQcoZnDo12NGCxWZDJpciZ * 📝 docs(skill): record dual-repo share verify and skeleton layout parity Claude-Session: https://claude.ai/code/session_01TQcoZnDo12NGCxWZDJpciZ * 👷 ci(share): keep overlay naming neutral in public workflow Claude-Session: https://claude.ai/code/session_01TQcoZnDo12NGCxWZDJpciZ * 👷 ci(share): reuse the existing overlay token secret Claude-Session: https://claude.ai/code/session_01TQcoZnDo12NGCxWZDJpciZ * ♻️ refactor: migrate lobe-cron to lobe-task (#18753) * 💄 style(share): center skeleton hero to match hydrated layout (#18756) Claude-Session: https://claude.ai/code/session_01TQcoZnDo12NGCxWZDJpciZ * 💄 style: register dedicated skeletons for all lazy routes (#18752) * 💄 style: add dedicated home route skeleton * 💄 style: register route skeletons for all lazy routes * ✅ test: align unit test mocks with base-ui component migration * ✅ test: complete base-ui mock alignment for migrated components Claude-Session: https://claude.ai/code/session_01UTDivfaszDuBjpPn7PV7gQ * 📌 chore: pin @lobehub/ui to 5.33.1 until base-ui migration completes Claude-Session: https://claude.ai/code/session_01UTDivfaszDuBjpPn7PV7gQ * ♻️ refactor: finish ActionIcon, Avatar, Tag and Text base-ui migration Completes #18729: migrates the 45 remaining call sites (plus type-only imports) to @lobehub/ui/base-ui and drops the temporary 5.33.1 pin now that the repo is clean under 5.33.3's expanded deprecation list. Claude-Session: https://claude.ai/code/session_01UTDivfaszDuBjpPn7PV7gQ * ♻️ refactor: migrate direct antd Tag and Avatar imports to base-ui Claude-Session: https://claude.ai/code/session_01UTDivfaszDuBjpPn7PV7gQ * ✅ test: stub base-ui ActionIcon in input banner queue case (#18760) * ✅ test: stub base-ui ActionIcon in input banner queue case The real base-ui ActionIcon requires the app-level MotionProvider, which the unit env does not set up. Claude-Session: https://claude.ai/code/session_01UTDivfaszDuBjpPn7PV7gQ * ✅ test: render real base-ui components via a global MotionProvider stub Redirect @lobehub/ui's internal MotionProvider module to a static stub in vitest config so base-ui components render in unit tests without the app-level ConfigProvider, and add composable canonical base-ui stubs (~base-ui-stubs) for tests that want simplified DOM. Claude-Session: https://claude.ai/code/session_01UTDivfaszDuBjpPn7PV7gQ * ✅ test: unblock closed antd-style factories against migrated base-ui imports Six antd-style mocks were closed factories missing createStaticStyles / keyframes / createGlobalStyle that real base-ui style modules now need; compose them over importOriginal. PluginTag and GroupItem retarget their UI stubs to the base-ui import path the components migrated to. Claude-Session: https://claude.ai/code/session_01UTDivfaszDuBjpPn7PV7gQ * ✨ feat: support workspace document comments (#18750) * ✨ feat: support workspace document comments * ✨ feat: enhance document comments with mentions and attachments * 🐛 fix: synchronize document comment activity * 🐛 fix: guard document comment attachment uploads * 🐛 fix: preserve comment synchronization metadata * 🐛 fix: scope document comment API routes * ✅ test: align base-ui component mocks * ✅ test: complete base-ui mock migration * ✅ test: clean up rebased component mock * ♻️ refactor: align comment imports with base-ui * ✅ test: align mocks with latest canary * 🐛 fix(connect-agent): prevent device loading state flash (#18768) * 🐛 fix(connector): canonicalize connector ownership (#18763) * 🐛 fix(eval): rm eval hints in run topic titles (#18771) * 🐛 fix(eval): isolate run topic titles * 🐛 fix(eval): keep ordinal topic titles * 🐛 fix(eval): retain run topic input * 🐛 fix(eval): remove fallback case label * 🐛 fix(agent): scope heterogeneous default names to shared workspaces (#18770) * 👷 ci: upgrade pnpm setup action to v6 (#18777) * 🐛 fix(queue): encode QStash deduplication IDs (#18778) * 🐛 fix(agent): recover sub-agent bridge answer from isolation thread for hetero children (#18781) * 🐛 fix(agent): recover the sub-agent bridge's answer from its isolation thread for hetero children callAgent-invoked heterogeneous (CLI-driven) sub-agents backfill their parent's placeholder tool message with "Sub-agent completed without a textual answer." even when the CLI produced a real reply — always, in production's queue mode (AGENT_RUNTIME_MODE=queue), not intermittently. completeSubAgentBridge/completeGroupActionMember resolve content from params.finalState, falling back to coordinator.loadAgentState(operationId) (the standard runtime's Redis-backed step state) when finalState isn't passed in-process. Both createSubAgentBridgeHook and createGroupActionMemberBridgeHook's webhook config deliberately strip finalState/lastAssistantContent from the QStash payload via `eventFields: ['operationId', 'reason', 'status']` (to keep the payload lean), so the queue-mode callback always arrives with finalState undefined — and hetero children never write into the coordinator's runtime state at all (confirmed zero `saveAgentState` calls under services/heterogeneousAgent/), so the fallback is structurally dead for them. heteroFinish already resolves the real answer server-side (via topics.metadata.heteroCurrentMsgId -> messageModel.findById) before dispatching, but that resolution never reaches the callback. Add resolveLastAssistantContentFromThread(threadId): queries the child's own isolation thread directly (thread ids are globally unique, no agentId/topicId needed to disambiguate) — the same source heteroFinish itself reads. Used as a fallback in both completeSubAgentBridge and completeGroupActionMember (isolated mode) when the existing finalState/coordinator resolution comes up empty, before falling through to the "no textual answer" stub. Two regression tests added (one per bridge method), reproducing the actual hetero shape (loadAgentState resolves null, not a message-stripped state) — verified to fail against the pre-fix code and pass with it. Full AgentRuntimeService.test.ts suite (114 tests) still passes. Fixes LOBE-13586 * 🐛 fix(agent): gate the thread content fallback on missing finalState Address a P2 flagged by Codex review on 15a401e: the thread-fallback guard checked only `!lastAssistantContent`, which also fires when a REAL, authoritative finalState is present but its last turn is legitimately textless (image-only, or the "preserve an empty leaf" case in normalizeCompletionMessages). In that case the fallback would still query the child's isolation thread — and a lagging read that surfaces an EARLIER real reply from the same thread would silently show stale text instead of the correct "no textual answer" stub. Narrow the guard to `!finalState` in both completeSubAgentBridge and completeGroupActionMember: this is exactly the heterogeneous-child case the fallback exists for (finalState is never populated for them at all), and `!finalState` already implies an empty lastAssistantContent, so nothing is lost for the case the fallback is meant to cover. Two regression tests added (one per bridge method) proving the fallback is never invoked when a real finalState says the answer is textless — verified to fail against the pre-fix (`!lastAssistantContent`) guard and pass with the narrowed one. Full AgentRuntimeService.test.ts suite (116 tests) passes. --------- Co-authored-by: AmAzing- <115673583+AmAzing129@users.noreply.github.com> Co-authored-by: Rdmclin2 <rdmclin2@gmail.com> Co-authored-by: YuTengjing <ytj2713151713@gmail.com> Co-authored-by: Innei <i@innei.in> Co-authored-by: Rylan Cai <67412196+cy948@users.noreply.github.com> Co-authored-by: Tsuki <76603360+sudongyuer@users.noreply.github.com> Co-authored-by: LiJian <onlyyoulove3@gmail.com>
# 🚀 LobeHub Release (20260827) **Release Date:** August 27, 2026 **Since v2.2.14:** 235 merged PRs · 13 contributors > This cycle makes long-running Agent work easier to direct and recover, expands provider-backed heterogeneous Agents, delivers safer restart-free Desktop updates, and deepens Artifact, Workspace, and acceptance workflows. --- ## ✨ Highlights - **Provider-backed heterogeneous Agents** — Claude Code and Codex gain deployment-backed model options, while Kimi Code and Pi add new provider paths across web and Desktop. (#18468, #18558, #18609, #18658, #18720, #18721) - **Restart-free Desktop updates** — Signed renderer updates apply in place with compatibility checks, compressed delta delivery, release-scoped artifacts, and automatic rollback. (#18648, #18694, #18716, #18724) - **Agent approval and intervention flows** — Agent approvals now align across surfaces, and generic interventions persist so long-running work can resume with the right user decision. (#18417, #18645) - **Agent self-learning** — A Labs-gated growth portrait shows learned domains, rules, and practice history while operation-scoped expertise improves future Work. (#18195, #18394, #18420) - **Public Artifacts and Workbench** — Local HTML and site assets can be packaged into versioned Artifacts, while acceptance and verification run in a standalone SSR Workbench. (#18424, #18473, #18569, #18728) - **Workspace collaboration** — Per-member Resource grants, transfer requests, and a redesigned Notification Center make shared work easier to control and act on. (#18389, #18432, #18536, #18545) - **More adaptable everyday UI** — Global interface fonts, consolidated Home promotions, clearer model availability, and refined recommendation visuals make the app easier to personalize and navigate. (#18712, #18722, #18730, #18741) --- ## 🏗️ Core Agent & Architecture ### Goals, Tasks & Acceptance - Goal state moves to a durable graph with dependency-aware scheduling, CLI controls, autonomous recovery, and terminal Acceptance Work. (#18574, #18597, #18635) - Scheduled Tasks get a dedicated view, successful subtasks complete automatically, and Kanban grouping matches the list view with clearer loading states. (#18586, #18591, #18631, #18707) - Acceptance deliveries group by Project and can be merged without losing checks, evidence, or prior review decisions; the review round now always reports its outcome. (#18448, #18537, #18548, #18672) - Acceptance features now share one consistent product boundary, while abandoned Goal Work and stale scoped tool calls recover instead of silently ending the run. (#18656, #18664, #18703) ### Agent Learning & Identity - Self-learning gains dedicated domain creation, editable anchors, operation-scoped Context, and safer lesson history management. (#18418, #18420, #18517, #18556) - Agent profiles gain a character sheet and reusable full-body artwork that retains its style and direction. (#18446, #18464) - Agent authors can restrict Topic sharing, while Agent transfers preserve accumulated expertise. (#18445, #18557) - Approval workflows align with web behavior, and generic interventions persist across Agent runs. (#18417, #18645) --- ## 📱 Platforms & Integrations ### Heterogeneous Agents - Claude Code supports local Provider bindings, while supported Claude Code and Codex runs can use deployment-backed models with operation-scoped authorization. (#18468, #18558, #18595, #18609, #18621) - Kimi Code joins heterogeneous Agent provider bindings, and Pi gains a dedicated Desktop provider path. (#18720, #18721) - Each Topic keeps its own heterogeneous model choice instead of rewriting the Agent default. (#18658) - Cursor moves to a bidirectional ACP session with permission prompts, questions, approvals, and safe resume recovery. (#18475) - OpenClaw and Hermes detection now covers official install paths, refreshed shell environments, and Windows launchers. (#18646) ### Desktop, Messaging & Gateway - Desktop applies verified renderer updates without restarting, keeps compact rollback deltas, and scopes OTA artifacts to the matching release. (#18648, #18694, #18716, #18724) - macOS communication notifications include Agent avatars, Workspace windows retain their bounds, and the terminal adds links and split panes. (#18430, #18433, #18441, #18500) - Gateways can pull the connection assignments they should hold, while message routing can still split platforms across deployments without changing the Integration protocol. (#18628, #18680) - Linked chat platforms receive Resource files and attachments with per-platform budgets, while scheduled Task results and rich Agent pushes appear in the Notification Center. (#18391, #18467, #18511, #18535, #18561, #18608) --- ## 🖥️ User Experience - Realtime voice dictation adds finalized speech to the editable draft without auto-sending or disturbing existing text and attachments, and its entry point now sits with the left-side chat actions. (#18132, #18578, #18709) - Home restores its marketing hierarchy, consolidates promotional surfaces, sharpens recommendation visuals, and brings back richer model shortcuts and the Apps catalog. (#18438, #18528, #18553, #18562, #18580, #18722, #18741) - A global interface font setting and locale-aware font stacks make reading preferences consistent across the app. (#18712) - GLM-5.3-Flash is available, disabled models can be re-enabled from chat input, and model prices survive OAuth redirects. (#18723, #18727, #18730) - Dead Topic locks no longer swallow sent messages, and completed gateway runs clear stale loading state in the sidebar. (#18497, #18682) - Agent document edits recover malformed persisted content and reject operations that would unexpectedly clear a non-empty document. (#18643) - Settings search covers more destinations and matches user queries more reliably. (#18390) --- ## 🔧 Tooling - Agent Chaos adds deterministic timeout, cleanup, tracing, and failure-injection contracts for long-running Agent tests. (#18667) - Evaluation Run Topics restore Test Case history and environment Context, and tool calls can be forwarded to mock servers for end-to-end verification. (#18516, #18604) - Workbench CI checks Worker bundle size and publishes PR previews after assets reach R2. (#18492, #18592) - Desktop release automation dispatches renderer OTA before native releases, and shared UI primitives continue moving to the base component layer. (#18716, #18729) - Obsolete Orb repository setup scripts are removed from the development path. (#18740) --- ## 🔒 Security & Reliability - **Security:** Resource checks stay scoped to the active Workspace and support per-member grants without bypassing privacy or role ceilings. (#18396, #18406, #18525, #18536, #18545) - **Security:** Server-default heterogeneous operations bind authorization to the user, operation, Workspace, and allowed capabilities. (#18558) - **Reliability:** Context compression avoids repeat work, removes compressed messages from queued payloads, and settles in-flight tool calls when interrupted. (#18506, #18587, #18610, #18626) - **Reliability:** Completed heterogeneous child Agents resume their parked parent, while RouterRuntime preserves request Context and retries the next configured channel on insufficient Provider balance. (#18596, #18668) - **Reliability:** Multi-tab settings changes no longer overwrite newer tool approval choices with stale state. (#18705) - **Performance:** Message-plugin and heterogeneous tool-call lookups avoid broad scans, and Task lists use a leaner database path. (#18457, #18519, #18618) --- ## 👥 Contributors Huge thanks to **13 contributors** who shipped **235 merged PRs** this cycle. @ONLY-yours · @orangeboyChen · @jalenzz · @NickShee · @BittuBarnwal7479 · @arvinxx · @Innei · @AmAzing129 · @rdmclin2 · @tjx666 · @sudongyuer · @cy948 · @nekomeowww --- **Full Changelog**: v2.2.14...release/weekly-20260827
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 : )