🚀 release: 20260513#14739
Conversation
* feat: avoid rebind link same account * chore: update i18n locales * feat: avoid discord account misslink * feat: support slack account mis match * fix: avoid claim conflict
…14559) * ✨ feat(task): add stop run action to activity card menu Surface the existing cancelTopic flow in the task detail activity card so users can interrupt a running topic without opening the chat drawer. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * ✨ feat(task): confirm before stopping a running topic Wrap the new Stop run action in a confirmModal so an accidental click can't silently abort an in-flight run. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 🐛 fix(spa): register /tasks and /task in SPA proxy matcher Without these matcher entries, the Next.js middleware never rewrote /tasks and /task/:taskId to the SPA catch-all, so the activity feed entries 404'd in production builds even though the routes were wired in the SPA router. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ndle (#14557) * 🐛 fix: sanitize sensitive comments and examples from production JS bundle - Replace app.example.com with RFC 2606 example.com in agent-browser skill content - Replace password-stdin examples with interactive auth prompts - Remove hardcoded password-like strings from code examples - Reword flagged code comments in page-agent system role Addresses TAC Security CASA Tier 2 DAST Info findings: Information Disclosure - Suspicious Comments (CWE-615) The flagged strings appeared in SPA production bundles: - /_spa/assets/chat-*.js - /_spa/assets/index-*.js * 🐛 fix: revert --interactive to --password-stdin in auth vault examples The --interactive flag does not exist in agent-browser CLI (only --password and --password-stdin are supported). Using --interactive would cause auth save to fail and block login workflows. Reverted both auth vault examples to use echo | --password-stdin pattern, which pipes the password via stdin — the recommended secure approach.
fix: add bot callback service
) * 📝 docs(version-release): enforce git-derived PR refs and metrics Add the skill's first-class hard rules for computing release-note inputs from git instead of memory: latest-tag base via `git describe`, PR refs from commit subjects, metric counts from `wc -l`, handle resolution via `gh pr view`, and a pre-publish `comm -23` diff that must be empty. Also adds @cy948 to the team roster and notes Tsuki / René Wang's commit-author aliases so contributor classification stops drifting. * ♻️ refactor(version-release): split skill into router + per-flow references SKILL.md was 426 lines covering three distinct flows. Split it so each flow lives next to its own checklist: - reference/minor-release.md — minor workflow (lifted from SKILL.md) - reference/patch-release-scenarios.md — patch flows (existing) - reference/release-notes-style.md — long-form changelog standard, template, and Computing Inputs hard rules (lifted from SKILL.md) SKILL.md now reads as a router (~100 lines) with shared CI trigger rules, post-release automation, precheck, and hard rules. Cross-links between references replace the previous in-file jumps. Also fixes a prettier-mangled redirect (`< some-pr-by-them >`) by using a `$PR` variable instead of an angle-bracket placeholder. * 📝 docs(version-release): add Hotfix and DB Migration variants to release-notes-style The Canonical Structure was implicitly long-form (Minor / Weekly), and hotfix authors had to read `changelog-example/hotfix.md` to learn it existed. Make the divergence explicit: - New § Variants for Shorter Releases describes Hotfix structure (Scope / What's Fixed / Upgrade / Owner) and DB Migration structure (Migration overview / Operator impact / Rollback) as overrides of the canonical long-form layout. - Renamed the canonical section to "Canonical Structure (Long-Form: Minor / Weekly)" so the boundary is visible. - Added Hotfix entry to Release Size Heuristics. - Added a Hotfix subsection to Quick Checklist so the verification gates differ from long-form (no metric line / no Contributors / Owner resolved via gh).
…text (#14568) * ✨ feat: Cloud Claude Code V3 — repo picker, GitHub token, sandbox context - Add CloudRepoSwitcher component (web-only multi-select repo picker) - Pre-topic selections buffered in module singleton (pendingTopicRepos) - Consumed by gateway.ts at topic creation time via appContext.initialTopicMetadata - Eliminates race condition where updateTopicMetadata dropped silently - Extend ChatTopicMetadata with repos[] field for multi-repo binding - Add initialTopicMetadata to ExecAgentAppContext so repos are written to topic metadata at creation time (server-side, zero race condition) - Extend ExecAgentSchema Zod schema with initialTopicMetadata - Inject GITHUB_TOKEN env var into sandbox so CC can use git/gh CLI - Build cloudHeteroContext with GitHub auth section when token is available - Add workingDirectory selector for web (repos[0] fallback) - Add refreshTopic call in gateway path after new topic creation - Add CloudHeterogeneousConfig profile editor for GITHUB_REPOS / GITHUB_CRED_KEY - Extend sandboxRunner with repo clone setup script and systemContext support * 🐛 fix: add open-source stub for pendingTopicRepos to fix Vite build * ♻️ refactor: move pendingTopicRepos real impl into submodule, remove cloud override * 🐛 fix: consume pendingTopicRepos only after topic creation succeeds * 🐛 fix: add missing getPendingTopicRepos import in gateway * 🔒 fix: address security and dead-code issues from PR review - sandboxRunner: sanitize repo dir name to prevent shell injection - sandboxRunner: use git insteadOf (-c flag) so token is never stored in .git/config - cloudHeteroContext: fix return type from string|undefined to string (dead branch) - CloudRepoSwitcher: remove unreachable empty-list branch in popover content Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * 💬 i18n: add claude setup-token hint to token description Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * 🐛 fix: remove incorrect web hetero→gateway forced routing in agentDispatcher On web, heterogeneousProvider is ignored — routing falls through to isGatewayMode. Cloud CC only runs when gateway mode is enabled; gateway.ts handles sandbox spawning when it detects a hetero provider. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * 🐛 fix: restore web hetero→gateway routing; update stale test On web, a configured heterogeneousProvider always routes to gateway — the cloud sandbox is the only execution environment regardless of isGatewayMode. The test assumed the pre-cloud-CC world where web ignored hetero providers entirely. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…nishing silently (#14577) * 🐛 fix(agent-runtime): recover malformed tool_call names instead of finishing silently When an LLM emits tool_call names without the `____` separator (e.g. `activateTools` instead of `lobe-activator____activateTools`), the resolver dropped them silently and the harness finished with "completed without tool calls" — empty assistant bubble, no error in dashboards. Three layers of defense: - Resolver fallback: when the bare name uniquely matches an API across known manifests, recover the identifier; ambiguous matches still drop to avoid false binding. - StreamingHandler logs unresolved tool_call names so the silent-drop path is observable in debug output. - GeneralChatAgent surfaces the unresolvable count and names in reasonDetail so dashboards can distinguish this from a genuine no-tool completion. Fixes LOBE-8696 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 🐛 fix(agent-runtime): restrict bare-name fallback to tools offered this turn Address review feedback on the LOBE-8696 resolver fallback. The manifests map passed to ToolNameResolver.resolve is broader than the tools actually sent to the LLM (the client builds it from every installed plugin and every builtin; the server can preserve manifests even after a step deactivates a tool). Without a turn-scope restriction: - A model returning a malformed bare name could resolve to a tool that was not enabled for this turn. - A disabled duplicate API name could shadow the enabled call and make it look ambiguous, dropping a valid call. Pipe an `offeredToolNames` list (the names actually sent in this LLM payload) into resolve(): when set, the missing-prefix fallback only considers manifests whose generated tool name appears in the list. - ToolNameResolver.resolve gains an optional `offeredToolNames` param. - internal_transformToolCalls forwards the list through. - createAgentExecutors builds resolvedAgentConfig before the StreamingHandler so the closure can bind the offered names — same list that gets sent to the model. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Migrate Notion to LobeHub Market
…ns (#14586) * ✨ feat: add signOperationJwt with 4h expiry for hetero-agent operations - Add `signOperationJwt(userId)` to internalJwt.ts with 4h expiry and `purpose: 'hetero-operation'`, so Claude Code / Codex tasks running beyond 5 minutes no longer hit 401 on heteroIngest / heteroFinish - Update `execAgent` hetero path to use `signOperationJwt` instead of `signUserJWT`; gatewayToken continues to use 5m `signUserJWT` - Add unit tests in `__tests__/internalJwt.test.ts` with correct mocks for `jose` (SignJWT class + importJWK) and `authEnv`, covering all three signing functions and the expiry difference assertion Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * 🔒 security: restrict hetero-operation JWT scope to heteroIngest/heteroFinish A leaked 4-hour sandbox LOBEHUB_JWT must not be replayable against any other authenticated lambda route. - Forward `purpose` claim from JWT payload through validateOIDCJWT → tokenData → oidcAuth context so middlewares can inspect it - oidcAuth: reject tokens with purpose 'hetero-operation' — they cannot reach any normal authedProcedure route - New heteroOperationAuth middleware: exclusively accepts purpose 'hetero-operation' tokens, rejects all others - Export heteroAuthedProcedure (baseProcedure + heteroOperationAuth + userAuth) from trpc/lambda/index.ts - heteroIngest / heteroFinish now use heteroAgentProcedure built on heteroAuthedProcedure + serverDatabase + HeterogeneousAgentService - Tests: heteroOperationAuth (4), oidcAuth (4), update heteroIngest test caller to supply purpose:'hetero-operation' context (23 total) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…ns to briefs, and automatically execute actions (#14583)
* feat: displayToolCalls default undefined * chore: restrict billboard to home page * fix: add slack bot scope * fix: show billboard in home nav
💄 style(QueueTray): use visible divider color between queued messages The previous `colorBorderSecondary` rendered the divider effectively invisible on the elevated dark surface. Switch to `colorFillTertiary` so stacked queued messages have a perceptible separator. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ingStatus (#14592) * 🐛 fix: skip reconnect when gateway action already established a connection Race condition on new-topic first message: 1. switchTopic loads runningOperation → useGatewayReconnect fires 2. executeGatewayAgent calls connectToGateway (status: connecting) 3. reconnectToGatewayOperation overwrites with resumeOnConnect:true 4. Gateway sees resume on a brand-new session → no events → stuck Second message works because the client store's runningOperation is stale (from the first op), so SWR deduplications and no reconnect fires. Fix: bail out of reconnectToGatewayOperation if gatewayConnections already shows connecting/connected for that operationId. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * 🐛 fix: always pass --cwd /workspace for cloud CC to ensure session resume CC stores session files at ~/.claude/projects/<encoded-cwd>/. Without an explicit --cwd the actual working directory can differ between sandbox invocations, so --resume <heteroSessionId> fails to locate the previous session files even though the container is persistent and the ID is correctly stored in topic.metadata. Default cwd to /workspace for cloud runs (desktop keeps its own explicit path), guaranteeing a stable session-file location across page reloads within the same sandbox lifecycle. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * 🐛 fix: extend reconnect guard to cover all in-flight connection statuses The previous guard only skipped reconnect for 'connecting'/'connected' but the connection can already be in 'authenticating' or 'reconnecting' by the time useGatewayReconnect fires, leaving the race window open. Flip the condition: skip for any status that is not 'disconnected'. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * 🐛 fix: restore cold replica state in HeterogeneousPersistenceHandler Vercel serverless functions are stateless per-request, so `operationStates` is empty on every `heteroIngest` call. loadOrCreateState always cold-creates. #14539 fixed `toolMsgIdByCallId` restoration but left `accumulatedContent`, `toolState.payloads`, and `toolState.persistedIds` empty on cold load, causing two bugs: - Content truncation: cold instance starts with `accumulatedContent=''`, accumulates only the current batch's text, then writes that shorter string on the next step boundary or terminal — overwriting the longer content the previous write had already stored in DB. - Tool duplication / tools[] overwrite: `persistedIds={}` on cold load means every `tools_calling` event re-creates already-persisted tool messages, and `payloads=[]` means phase 1/3 writes only the current batch's tools, wiping previous tools from `assistant.tools[]`. Fix: in `loadOrCreateState`, fetch the current assistant message and restore `accumulatedContent`, `accumulatedReasoning`, `toolState.payloads`, and `toolState.persistedIds` from it. Cold load is now equivalent to warm load. Also adds two regression tests covering the cold-replica scenarios. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…14589) * ✨ feat: home daily brief with linkable welcome + paired input hint Add a per-user "daily brief" surface to the home page. A cron-driven backend (in the cloud repo) writes paired { welcome, hint } entries into Redis under `aiGeneration:home_brief:{userId}`. This change exposes that data through: - `RedisKeys.aiGeneration.homeBrief` key builder - `home.getDailyBrief` lambda router query that reads the cached payload - `homeService.getDailyBrief` client and `useHomeDailyBrief` hook with shared rotating index via `useSyncExternalStore` - `WelcomeText` runs a custom typewriter (supports real `\n` line breaks and parses inline `[label](url)` markdown links so cached entity references become clickable; falls back to the i18n welcome list) - `InputArea` shows the matching hint as the chat input placeholder Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * ♻️ refactor: extract daily-brief Redis read into HomeService Mirrors the AgentService pattern: the lambda home router was reaching into Redis directly, which mixed I/O concerns with the routing layer. Move the read into a dedicated `HomeService` so future home-page reads have a clear home and the router stays thin. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 🐛 fix: keep WelcomeText typewriter index in sync with shared store Before: DailyTypewriter held its own `sentenceIndex` state, separate from the module-level `currentIndex` in `useHomeDailyBrief`. After the home page rotated past the first pair, navigating away and back remounted the typewriter and reset its local index to 0 — but the external index stayed where it was. InputArea read the hint at the stale external index while WelcomeText restarted at pair 0, breaking the welcome / hint pairing. Make the typewriter fully controlled: drop the local `sentenceIndex`, expose `currentIndex` from `useHomeDailyBrief`, and pass it as a prop. On `pause`, the typewriter just calls `onSentenceComplete` — the parent flips the shared index, the new prop flows back, the reset effect re-arms typing for the new sentence. Single source of truth, remount-safe. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * ♻️ refactor(redis): factor JSON cache reads into getJSONFromRedis util Three call sites were inlining the same "fetch + null-check + JSON.parse + try/catch" recipe against a scoped Redis client: - AgentService.getAgentWelcomeFromRedis - HomeService.readDailyBriefFromRedis (new) Move the recipe into a small `getJSONFromRedis<T>` helper next to the other Redis utilities and have both services delegate to it. Caller keeps responsibility for resolving the right scoped client (we don't want to hide the prefix selection inside the helper). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 🐛 fix(home): use live editor content for Enter-to-send guard When typing into the home input and pressing Enter immediately, the empty-message guard sometimes wrongly bailed out. The cause: the guard read the cached `inputMessage` in `useChatStore`, which is populated by the editor's async `onMarkdownContentChange`. Lexical commits its update on a microtask after each keystroke, so a fast type-then-Enter fires the send path before the cache catches up. `SendButtonHandler` already passes `getMarkdownContent` through — read it instead, falling back to the cached value if the handler is invoked without it. Also propagate the live message into all `inputActiveMode` branches. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * ✨ feat(home): accept daily-brief hint as the message on empty Enter Press Enter on the empty home input → send the currently displayed daily-brief hint as the message (smart-compose / Tab-to-accept style). Trims the cosmetic trailing ellipsis and rotates the carousel so the next press picks up a different pair. Falls through to the previous "no content, skip" path when there's neither a typed message nor a hint to use. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 🐛 fix(home): scope daily-brief SWR key + rotation index by userId The SWR key was a constant string, so an account switch within the same SPA session — sign out + sign in as another user, or a multi-account swap that keeps `isSignedIn` true — could surface the previous user's cached pairs from the same slot. The keyspace in Redis is per-user, so the served data leaks personalization. Include the resolved userId in the SWR key, and reset the module-level rotation index on user change so the new account starts from pair 0 rather than inheriting a stale offset (which could also point past the end of a smaller pairs list). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
✨ feat(topic): add copy session ID to topic dropdown menu Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
#14567) Co-authored-by: YuTengjing <ytj2713151713@gmail.com>
…` tail (#14596) * 🐛 fix(agent-runtime): forward pluginState through gateway client tool result Gateway-mode client tool results lost the `state` field at three points: the toolResult Zod schema didn't declare it (silently stripped by safeParse), the ToolResultPayload interface didn't carry it, and projectToExecutionResult didn't return it. As a result the "技能状态" tab was always empty for tools dispatched via Agent Gateway, even though clients send `state` correctly and non-gateway paths persist it as `pluginState`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 🐛 fix(prompts): suppress redundant `Exit code: 0` tail in command result For successful runs, "Command completed successfully." already conveys the same signal — appending "Exit code: 0" was just noise the LLM had to skim past. Non-zero exit codes (130 SIGINT, 137 OOM, etc.) keep the line so the diagnostic information remains available. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 🐛 fix(prompts): treat non-zero exit code as command failure in result header `success` is the envelope ("the service responded") and `exitCode` is the command's own status — they're independent. With `success: true` + `exitCode: 137` the prior format rendered "Command completed successfully." on top of a SIGKILL/OOM, lying to the LLM. Now the header is derived from both: any non-zero exit folds the message into the failure branch as "Command failed with exit code N[: error]". The trailing "Exit code: N" line is gone — the same info now lives in the header, so success rendering is also free of the redundant zero tail. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot <copilot@github.com> Co-authored-by: YuTengjing <ytj2713151713@gmail.com>
… Lambda crash (#14606) * 🐛 fix(database): attach error listeners to Neon/Node pools to prevent Lambda crash NeonPool (and NodePool) inherit pg.Pool semantics: when a backend connection drops on an idle client the pool emits 'error'. With no listener Node escalates that into uncaughtException — on Vercel this killed the entire Lambda process (exit 129) and produced a 1805-crash avalanche in 5 minutes, spiking Neon connection count from 30 to 330+ as half-closed sockets accumulated (LOBE-8704). Primary fix: attach `.on('error', ...)` to both pool variants in `packages/database/src/core/web-server.ts` so the error is logged but swallowed; the pool recovers on its own per pg docs. Defense in depth: register `uncaughtException` / `unhandledRejection` handlers in `instrumentation.ts` (gated to nodejs runtime) so any future unhandled error doesn't take down the process either. Refs: https://node-postgres.com/apis/pool#error Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 🔧 chore: drop process-wide uncaughtException handler Per review on #14606: the catch-all listener in instrumentation.ts swallowed every uncaughtException / unhandledRejection — not just NeonPool errors — leaving the process in an undefined state instead of letting the platform restart it, and would mask future production bugs. LOBE-8704 is fully addressed by the targeted pool listeners in packages/database/src/core/web-server.ts; the broad backstop is unnecessary and unsafe. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…tch(...)` instead of hardcoded normalizer (#14590)
…14728) 🌐 i18n: add missing translations for task-schedule and review keys across 16 locales Adds 14 missing i18n keys to all non-zh-CN locales (ar, bg-BG, de-DE, es-ES, fa-IR, fr-FR, it-IT, ja-JP, ko-KR, nl-NL, pl-PL, pt-BR, ru-RU, tr-TR, vi-VN, zh-TW): chat.json (11 keys): - taskSchedule.summary.everyNHoursHalfPast - taskSchedule.summary.hourlyHalfPast - taskSchedule.timezoneSearchEmpty - taskSchedule.timezoneSearchPlaceholder - workingPanel.review.revert (and 7 sub-keys) plugin.json (1 key): - builtins.lobe-task.apiName.setTaskSchedule setting.json (2 keys): - serviceModel.modelAssignments.title - serviceModel.optionalFeatures.title These were added in recent commits but the automated i18n sync had not yet propagated them to non-Chinese locales.
…text menu (#14727) * ✨ feat(markdown): render <user_feedback> task prompt blocks as a card `buildTaskRunPrompt` wraps the user's pre-run comments in a `<user_feedback>` block alongside `<task>`. The Task plugin captured `<task>` into a card, but `<user_feedback>` had no plugin and leaked into the chat as raw XML. Because CommonMark only treats tag names matching `[a-zA-Z][a-zA-Z0-9-]*` as html, the underscore in `user_feedback` puts the opening/closing tags inside a `paragraph` as plain text — so the new remark plugin walks paragraph children rather than html nodes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 💄 style(task-card): drop standalone status row + Agent/Parent/Topics, inline semantic status badge The status/Priority row, Agent, Parent and Topics fields aren't useful when the task card is rendered inside the topic chat drawer (the drawer already exposes that context). Move the task status to a compact badge beside the identifier and reuse `taskDetail.status.*` for the label so "scheduled" reads as "Scheduled" / "已排期". Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 💄 style(user-feedback): compact one-line header + left-border quote-style card Slims the card down to a single 12px header line ("User feedback · N comments") with a small 12px icon, and wraps the whole block in a subtle fill + 2px left-border accent so it reads as a quoted aside and visually separates from the task card that follows in the same user message body. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 💄 style(user-feedback): drop fill + radius, render as plain left-rail blockquote The filled card competed visually with the unstyled task block that sits beside it in the same message body. Reducing to a 2px left-rail quote without background or border-radius lets both blocks read as parts of the same user message. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 💄 style(user-feedback): collapsible card with task-style head + bottom divider Default-collapsed `<details>` whose summary mirrors the task title row (32px icon + bold label + small count badge), with a bottom split-line that doubles as a divider between the user feedback head and the task card that follows in the same message body. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 💄 style(user-feedback): strip default markdown details card chrome @lobehub/ui Markdown applies bg + padding (0.75em 1em) + box-shadow + border-radius to every nested <details>, which made the user_feedback head read as a wide standalone card sitting awkwardly on top of the inline task title. Override the chrome (with !important — the lib selector wins on specificity otherwise) so the head sits flat in the message body, with only the bottom split line separating it from the task that follows. The lib's right-side disclosure chevron is kept. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 💄 style(user-feedback): match task card's 12px symmetric divider spacing Add a 12px margin-bottom so the gap below the user_feedback bottom rule mirrors the 12px above it, matching the symmetric 12px the task card already uses around its own internal divider. Without this, the user_feedback rule sat flush against the T-31 row while the next rule below T-31 had a 12px gap on both sides — visually uneven. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 💄 style(task-card): drop status badge from task title row The task drawer header and the schedule strip on the task detail page already convey status; surfacing it again on the task card inside the chat body just added noise. Drop the badge along with the now-unused KNOWN_STATUSES / isKnownStatus / TaskStatusIcon / useTranslation plumbing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * ✨ feat(tasks): add "Run now" item to task card context menu Available only for backlog and completed tasks; mirrors the inbox-agent fallback used by the detail-page Run Now action. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 🐛 fix(topic-list): preserve `#` icon placeholder for heterogeneous agents Returning null for the icon slot collapsed the row layout, so titles on heterogeneous-agent topics (Claude Code, Codex, …) no longer aligned with sibling rows. Render the same HashIcon with visibility:hidden so the box is preserved without showing the glyph. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…14660) * 🐛 fix(web-crawler): cap response body size to prevent serverless OOM Production saw repeated SIGABRT crashes on `/trpc/tools/search.webSearch` where Node aborted with V8 "allocation failed" — the naive crawler buffered entire response bodies into heap before the 1 MB downstream truncation could apply, so a single large page (or a batch of three under default concurrency=3) could push rss past the lambda memory ceiling. - ssrfSafeFetch: add opt-in `maxContentLength` that streams the response body via `for await` and stops at the cap (soft truncation — still a successful response). Breaking the iterator destroys the underlying stream and releases the connection. Default behaviour (full `arrayBuffer()` read) unchanged when the option is absent. - naive crawler: pass `maxContentLength: MAX_HTML_SIZE` so any body beyond 1 MB is dropped at the network layer instead of being materialised in heap. - htmlToMarkdown: explicitly call `window.happyDOM.close()` in a finally block so the parsed DOM tree is released as soon as parsing finishes, rather than waiting for the function scope to drop. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * ✅ test(ssrf-safe-fetch): add OOM regression tests for response body cap Verify that the maxContentLength cap actually prevents the production SIGABRT scenario, not just produces a truncated body. - Source-pull bound: a body source with 200 MB available, capped at 1 MB, must not be drained beyond ~1 MB. Asserts on bytes pulled from the generator, which is the property that prevents OOM. - Concurrency bound: matches production CRAWL_CONCURRENCY=3 — three concurrent oversized fetches should pull at most ~3 MB total, not 300 MB. - Heap-delta bound (gated on --expose-gc): under real GC pressure, fetching a 50 MB body with a 1 MB cap should grow heapUsed by < 10 MB. Run with `NODE_OPTIONS=--expose-gc bunx vitest run` to exercise; skipped by default so CI doesn't false-fail on GC timing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… locale (#14730) * 🐛 fix(task-card): localize date format independent of dayjs global locale Task card was rendering "5月 12" under English UI because t('time.formatThisYear') returned the English "MMM D" format, but dayjs's global locale was still zh-cn, making MMM resolve to the Chinese short month name. Thread the i18n language into formatTaskItemDate so the date is rendered with the same locale as the format string, decoupling it from dayjs's global state. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 🐛 fix(task-card): import missing GenericItemType + type Run now onClick Pre-existing CI regression from #14727 surfacing on every PR: the Run now context menu satisfies-clause references GenericItemType without importing it, and the onClick lacks a MenuInfo annotation, so tsgo widens the divider literal's `type` to `string` and rejects the whole context menu array. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ntionHandler, stepPresentation (#14441) * ♻️ refactor(agent-runtime): extract CompletionLifecycle Pull terminal-state handling out of AgentRuntimeService into a dedicated class: - buildLifecycleEvent (was buildCompletionLifecycleEvent) - emitSignalEvents (was emitCompletionSignalEvents) - dispatchHooks (was dispatchCompletionHooks) - extractErrorMessage These four methods formed one cohesive vertical: build the lifecycle event payload, emit completion AgentSignal source events, dispatch onComplete/onError hooks, and write error back onto the assistant message row. extractErrorMessage was a private helper used by all three plus by the trace-snapshot finalize call site, so it becomes a public method on the class. Call sites in executeStep / executeSync change from `this.{emit|dispatch|extract...}` to `this.completionLifecycle.{...}`. Tests: extractErrorMessage.test.ts → CompletionLifecycle.test.ts, instantiating CompletionLifecycle directly instead of going through AgentRuntimeService — drops a pile of unrelated mocks. AgentRuntimeService.ts: 2084 → 1918 (-166). All 81 agentRuntime tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * ♻️ refactor(agent-runtime): extract HumanInterventionHandler Pull the 165-line `handleHumanIntervention` method out of AgentRuntimeService into its own class, splitting the three branches (approve / rejectAndContinue / rejectAndHalt) into private methods so each fits in one screen. Routing in `process()` now reads top-to-bottom: detect approval, then rejection, then unsupported humanInput. The handler depends only on `serverDB` (for the messagePlugins lookup) and `messageModel` (for tool/plugin updates) — much narrower than AgentRuntimeService's full surface, so the extracted unit is easier to unit-test in isolation. Drop the unused `runtime: AgentRuntime` parameter from the public API: the original method threaded it through but never called it. Tests: handleHumanIntervention.test.ts → HumanInterventionHandler.test.ts — same 17 cases, but instantiate the handler directly instead of constructing a full AgentRuntimeService with 11 module mocks. Tighter arrange step, same coverage. AgentRuntimeService.ts: 1918 → 1742 (-176). All 81 agentRuntime tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * ♻️ refactor(agent-runtime): extract step presentation builder Pull the ~150-line `phase`-branching block out of executeStep into a pure `buildStepPresentation` function. The block did three things in sequence: derive content/reasoning/toolsCalling/toolsResult from the runtime step result, build a one-line stepSummary for logging, and assemble the StepPresentationData DTO consumed by afterStep hooks / snapshot recorder / callbacks. The function takes only the stepResult and an executionTimeMs; no service state needed. Comes with a `formatTokenCount` helper for the log line (12345 → 12.3k, 2_500_000 → 2.5m). executeStep keeps the log call inline (one line, references presentation fields directly) and reads `content` / `toolsCalling` off presentation for downstream tracking + truncation logic. 13 new unit tests: phase=tool_result (json + string + isSuccess paths), phase=tools_batch_result, done event, llm_result with content/reasoning/ tools, empty fallback, cumulative usage zero-fallback, stepUsage forwarding, and formatTokenCount edges. AgentRuntimeService.ts: 1742 → 1601 (-141). All 94 agentRuntime tests pass (was 81, +13 new). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…14584) 🐛 fix: prevent synthetic scroll from shrinking spacer
✨ feat(database): add agent_operations table Adds an `agent_operations` table to persist agent runtime operations beyond the 2-hour Redis TTL. Each row captures one agent operation (operationId) with denormalized cost/token aggregates, lifecycle timestamps, runtime config snapshot, and a `trace_s3_key` pointer to the full ExecutionSnapshot in S3. - `user_id` is intentionally not a FK so operation history survives user deletion (auditable historical data). - `agent_id` / `topic_id` / `thread_id` / `task_id` / `chat_group_id` use ON DELETE SET NULL to preserve operations when their parent entity is removed. - `parent_operation_id` self-references for sub-agent (callAgent) ops. - `human_interventions` and `human_waiting_time_ms` are nullable since most operations have no human interaction at all. - Indexes optimize per-user listing and per-status / per-entity lookups; `metadata` has a GIN index for jsonb filters.
) When the home input was empty and the user clicked send, `useSend` correctly fell back to the daily-brief hint for `message`, but it also forwarded `mainInputEditor.getJSONState()` as `editorData`. An empty editor still returns a non-null JSON state (e.g. `{ type: 'doc' }`), which makes `UserMessageContent.hasEditorData` truthy — so the renderer took the RichTextMessage branch and drew nothing, while the agent happily processed the hint text behind a blank user bubble. Skip `editorData` when the hint is being used so the renderer falls back to the markdown `content`. Adds a regression test. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…nent (#14703) * 💄 style(home,i18n): use 已阅 for brief confirm/confirmDone in zh-CN Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 🐛 fix(home): use 确认完成 for brief.action.confirmDone in zh-CN confirmDone signals the terminal transition (task marked complete), not just dismissing the brief, so 已阅 loses the semantic distinction from `confirm`. Use 确认完成 to match the EN intent ("Confirm complete"). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * ♻️ refactor: use @lobehub/ui built-in HtmlPreview instead of custom component - Upgrade @lobehub/ui from ^5.10.1 to ^5.10.4 - Replace custom HtmlPreviewAction with lobe-ui's enableHtmlPreview - Wire lobe-ui's onExpand callback to existing HtmlPreviewDrawer - Remove HtmlPreviewAction.tsx (no longer needed) - Keep HtmlPreviewDrawer for the expanded full-screen view * 🐛 fix(task): sync useMarkdown destructuring with assistant MessageContent * 🐛 fix(task): correct mangled search.X JSX expressions in MessageContent Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 💄 style(review): move revert icon to right edge of file row Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… `lobe-agent` (#14715) * ♻️ refactor(builtin-tool): move sub-agent dispatch from lobe-gtd to lobe-agent Move the `execTask` / `execTasks` capability out of `packages/builtin-tool-gtd/` and into `packages/builtin-tool-lobe-agent/`, renaming the public APIs to `callSubAgent` / `callSubAgents`. The "subtask" naming inside GTD overlapped with the new lobe-task tool's task model and conflated planning with sub-agent dispatch. - API names: `execTask` → `callSubAgent`, `execTasks` → `callSubAgents` - TS types: `ExecTaskParams` → `CallSubAgentParams`, etc.; introduce `SubAgentTask` to replace `ExecTaskItem` - Client UI (Inspector / Render / Streaming) ported under `packages/builtin-tool-lobe-agent/src/client/` - Central registries (`packages/builtin-tools/src/{inspectors,renders,streamings}.ts`) updated to register lobe-agent - GTD `meta.description` and system role no longer mention async tasks; they point to lobe-agent for sub-agent dispatch - `isSubTask` filtering in `agentConfigResolver` now excludes `lobe-agent` (new owner of sub-agent dispatch) instead of `lobe-gtd` - i18n: new `builtins.lobe-agent.apiName.callSubAgent*` and `workflow.toolDisplayName.callSubAgent*` keys in default/zh-CN/en-US Kept the executor's emitted `state.type` values (`execTask` / `execTasks` / `execClientTask` / `execClientTasks`) unchanged so the agent-runtime instruction layer (`exec_task` / `exec_tasks` / `exec_client_task*`) and all downstream tests / heterogeneous executors (`builtin-tool-agent-management`, server `agentManagement` runtime) continue to work without modification. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * ♻️ refactor(chat): rename isSubTask flag to isSubAgent After moving sub-agent dispatch from lobe-gtd to lobe-agent, the flag name no longer matches what it controls. Rename `isSubTask` → `isSubAgent` across the chat / agent runtime layer and update related comments and test labels. - `agentConfigResolver` context field + filter helper - `streamingExecutor.internal_createAgentState` + `executeClientAgent` signatures and call sites - `createAgentExecutors` (exec_task / exec_client_task handlers) and `GroupOrchestrationExecutors` (batch_exec_async_tasks) - `chatService.createAssistantMessageStream` `resolvedAgentConfig` docs - Test descriptions and assertions in `agentConfigResolver.test.ts` and `streamingExecutor.test.ts` No behavior change — the flag's filter target (`lobe-agent` identifier) is unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * ♻️ refactor(agent-runtime): rename exec_task wire identifiers to exec_sub_agent Bring the agent-runtime "wire" naming in line with the lobe-agent callSubAgent / callSubAgents API rename. Three layers are renamed in lockstep to keep the bridge between tool executors and the runtime consistent: 1. Tool-emitted state.type discriminators - 'execTask' → 'execSubAgent' - 'execTasks' → 'execSubAgents' - 'execClientTask' → 'execClientSubAgent' - 'execClientTasks' → 'execClientSubAgents' 2. AgentInstruction.type and matching TS interfaces - 'exec_task' / 'exec_tasks' / 'exec_client_task' / 'exec_client_tasks' → 'exec_sub_agent' / 'exec_sub_agents' / 'exec_client_sub_agent' / 'exec_client_sub_agents' - AgentInstructionExecTask → AgentInstructionExecSubAgent (and the three siblings) - ExecTaskItem → SubAgentTask 3. AgentRuntimeContext.phase + matching payload types - 'task_result' → 'sub_agent_result' - 'tasks_batch_result' → 'sub_agents_batch_result' - TaskResultPayload → SubAgentResultPayload - TasksBatchResultPayload → SubAgentsBatchResultPayload Also renames the operation-type discriminator 'execClientTask' / 'execClientTasks' to 'execClientSubAgent' / 'execClientSubAgents' and updates its locale string in default / zh-CN / en-US. Tests / fixtures / mocks updated in lockstep: - packages/agent-runtime/src/agents/{GeneralChatAgent.ts,__tests__/...} - packages/builtin-tool-{lobe-agent,agent-management}/src/... - src/server/services/toolExecution/serverRuntimes/agentManagement.ts - packages/agent-mock/src/cases/builtins/todo-write-stress.ts (helper renamed to callSubAgent) - src/store/chat/agents/createAgentExecutors.ts + exec-task / exec-tasks tests + fixtures/mockInstructions.ts (createExecSubAgent[s]Instruction) - src/store/chat/slices/aiChat/actions/streamingExecutor.ts (phase check) - packages/conversation-flow/src/__tests__/fixtures/**/*.json (8 fixtures retargeted from lobe-gtd/execTask[s] to lobe-agent/callSubAgent[s] with the new state.type wire values) No behavior change — the agent runtime, executors and tests all go through the same code paths; only the strings on the wire change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * ♻️ refactor(builtin-tool): absorb GTD tool (plan + todo) into lobe-agent Delete `packages/builtin-tool-gtd/` and fold its full surface — plan, todo, ExecutionRuntime, all client UI (Inspector / Render / Streaming / Intervention / SortableTodoList) and the system role — into `packages/builtin-tool-lobe-agent/`. Single `lobe-agent` identifier now owns: plan + todo management, sub-agent dispatch, and visual media analysis. Also restructures the lobe-agent package so the executor lives under `./client/` alongside the UI it ships with, and drops the dedicated `./executor` export — consumers go through `./client` for everything client-side. Package-level changes: - DELETE `packages/builtin-tool-gtd/` entirely. - `packages/builtin-tool-lobe-agent/` - Move `src/executor/` → `src/client/executor/`. Drop `./executor` from `package.json` exports; expose `lobeAgentExecutor` via `./client` only. - Rename `GTDExecutionRuntime` → `PlanExecutionRuntime` and place under `src/client/executor/PlanRuntime/`. Re-export from package root so the server runtime can consume it without pulling in client UI deps. - Extend `LobeAgentExecutor` with `createPlan` / `updatePlan` / `createTodos` / `updateTodos` / `clearTodos`, all delegated to the shared runtime. - Add Plan + Todo API entries to the manifest (with their original descriptions, humanIntervention, renderDisplayControl). - Move all GTD client UI verbatim: `Inspector/{ClearTodos,CreatePlan,CreateTodos,UpdatePlan,UpdateTodos}`, `Render/{CreatePlan,TodoList}`, `Streaming/CreatePlan`, `Intervention/{AddTodo,ClearTodos,CreatePlan}`, `components/SortableTodoList`. Register them in `LobeAgentInspectors / Renders / Streamings`, add new `LobeAgentInterventions`. - Merge GTD system role into lobe-agent's (`<plan_and_todos>` plus the existing `<sub_agents>` and `<run_in_client>` sections). - `package.json`: pick up `@lobechat/prompts` dep and `@lobehub/editor` + `antd` + `lucide-react` peer-deps inherited from GTD. Central registries (`packages/builtin-tools/src/*`) and consumers: - Remove every `GTDManifest / Inspectors / Renders / Streamings / Interventions` import + registration; existing `LobeAgent*` registrations now cover them. - Replace `[GTDManifest.identifier]: GTDInterventions` with `[LobeAgentManifest.identifier]: LobeAgentInterventions`. - Drop `@lobechat/builtin-tool-gtd` workspace dep from `packages/builtin-tools/package.json`, `packages/builtin-agents/package.json` and root `package.json`. - Remove `gtdExecutor` from `src/store/tool/slices/builtin/executors/index.ts`; switch `lobeAgentExecutor` import to `/client`. - Replace `serverRuntimes/gtd.ts` with a service factory `serverRuntimes/lobeAgentPlan.ts` (`createServerPlanRuntimeService`). `serverRuntimes/lobeAgent.ts` instantiates `PlanExecutionRuntime` with that service so the registry exposes one runtime per `lobe-agent` identifier covering both visual analysis and plan/todo. - `services/chat/mecha/contextEngineering.ts`: gate plan/todo injection on `LobeAgentIdentifier` instead of `GTDIdentifier`. - `agentConfigResolver.test.ts`: switch fixture plugin IDs to `LobeAgentIdentifier`. - `packages/const/src/recommendedSkill.ts`: drop the standalone `lobe-gtd` recommendation — `lobe-agent` already covers it via `defaultToolIds`. i18n migration (default + zh-CN + en-US; other locales regenerate on `pnpm i18n`): - `builtins.lobe-gtd.*` → `builtins.lobe-agent.*` in `plugin.ts/json`. - `lobe-gtd.*` (tool namespace) → `lobe-agent.*` in `tool.ts/json`. - Remove `tools.builtins.lobe-gtd.{description,readme,title}` from `setting.ts/json` (lobe-agent has its own meta now). - Update all client component `t(...)` keys to the new namespace. Mocks / fixtures / tests: - `packages/agent-mock/src/cases/builtins/todo-write-stress.ts`: all `identifier: 'lobe-gtd'` → `'lobe-agent'`; helper comments updated. - `packages/types/src/stepContext.ts`: comment refers to `builtin-tool-lobe-agent` (the only consumer of `StepContextTodoItem`). - `packages/model-runtime/src/core/streams/google/google-ai.test.ts`: function-call names from `lobe-gtd____createPlan` etc. → `lobe-agent____*`. - `src/store/chat/slices/message/selectors/dbMessage.test.ts`: same. - `src/features/DevPanel/RenderGallery/fixtures/lobe-gtd.ts` deleted; its plan/todo fixtures are folded into `fixtures/lobe-agent.ts` alongside the existing `callSubAgent[s]` ones. - Replace `console.log` → `console.info` in moved client components to satisfy lobe-agent's stricter ESLint rules (GTD package allowed `console.log`; lobe-agent inherits the repo-wide `no-console` rule). No behavior change for end users: `lobe-agent` now owns all the APIs, identifiers, and UI that previously lived in `lobe-gtd`, but as a single consolidated package under a single tool identifier. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * ♻️ refactor(context-engine): drop residual GTD naming, rename to PlanInjector / TodoInjector Follow-up to 9ca5c9d (which absorbed the GTD tool package into lobe-agent). That commit moved the package surface but left the GTD vocabulary embedded in context-engine providers, types, metadata fields, XML tags, and a pile of comments. This change finishes the sweep so the only remaining GTD references are user-facing docs and the legitimate Productivity & GTD Coach methodology suggestion. context-engine - `GTDPlanInjector` → `PlanInjector`; types `GTDPlan`/`GTDPlanInjectorConfig` → `Plan`/`PlanInjectorConfig`; metadata `gtdPlanId`/`gtdPlanInjected` → `planId`/`planInjected`; XML tag `<gtd_plan>` → `<plan>`; debug channel `provider:GTDPlanInjector` → `provider:PlanInjector`. - `GTDTodoInjector` → `TodoInjector`; types `GTDTodoItem`/`GTDTodoList`/ `GTDTodoStatus`/`GTDTodoInjectorConfig` → `TodoItem`/`TodoList`/ `TodoStatus`/`TodoInjectorConfig`; metadata `gtdTodo*` → `todo*`; XML tag `<gtd_todos>` → `<todos>`, wrapper `gtd_todo_context` → `todo_context`; debug channel renamed similarly. - `MessagesEngineParams.gtd?: GTDConfig` → `planTodo?: PlanTodoConfig`; internal vars `isGTDPlanEnabled`/`isGTDTodoEnabled` → `isPlanEnabled`/`isTodoEnabled`. Re-exports updated in `providers/index.ts` and `engine/messages/{index,types}.ts`. prompts - `packages/prompts/src/prompts/gtd/` → `planTodo/` (only export was `formatTodoStateSummary`, which kept its name). Updated `prompts/index.ts` re-export. src/services - `contextEngineering.ts`: `GTDConfig` import → `PlanTodoConfig`; `isGTDEnabled`/`gtdConfig` → `isPlanTodoEnabled`/`planTodoConfig`; payload field `gtd` → `planTodo`; log message wording. Tests - `dbMessage.test.ts`: helper `createGTDToolMessage` → `createLobeAgentToolMessage`; `gtdMessage` → `lobeAgentMessage`; all `it` descriptions reworded to "lobe-agent" instead of "GTD". - `agentConfigResolver.test.ts`: test descriptions reworded. Comments / docs (no behavior change) - agent-runtime (`instruction.ts`, `runtime.ts`, `generalAgent.ts`, `messageSelectors.ts`), `types/{stepContext,tool/builtin}.ts`, `builtin-agents/group-supervisor`, `builtin-tool-claude-code/types.ts`, `builtin-tool-lobe-agent/Render/TodoList`, `createAgentExecutors.ts:1426`, `AssistantGroup/{constants,Fallback.test}`, `agent-mock/todo-write-stress`, `.agents/skills/builtin-tool/references/architecture.md`. Intentionally left alone - `docs/usage/agent/gtd.{mdx,zh-CN.mdx}` and other docs — user-facing product brand "GTD Tools". - `src/locales/default/suggestQuestions.ts` "Productivity & GTD Coach" — references the methodology, not the tool. - `ToolSystemRoleProvider.test.ts` `'gtd-tool'` fixture — generic test identifier, unrelated. - Translated locale files still carrying `lobe-gtd.*` keys — regenerated by `pnpm i18n` from the updated default namespace. Verified: `bun run type-check` passes; touched test files (dbMessage, agentConfigResolver) and full context-engine + prompts test suites pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 🐛 fix(builtin-tool-lobe-agent): reset TodoList auto-save status to idle `performSave` (the debounced auto-save path) was leaving `saveStatus` stuck on 'saved' forever — `saveNow` had the 1.5s setTimeout-to-idle but the auto-save twin didn't, so the inline indicator never eased back to idle after a settle. Add the same idle-reset to performSave so both paths behave the same. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…14732) Close the wire-protocol gap that left CC's AskUserQuestion form stuck on "pending" after the bridge gave up. AskUserBridge now emits an agent_intervention_response event on every terminal path (timeout, user resolve, cancel, cancelAll), and heterogeneousAgentExecutor handles it by stamping pluginIntervention.status = 'rejected' for timeout / session_ended (user-driven paths are filtered out — already optimistic). Layered defenses so a late Submit no longer throws "Operation not found": - cleanupCompletedOperations: find→filter so every messageOperationMap entry pointing to the cleaned op is removed (assistant + tool message pairs previously stranded one entry as a dangling reference). - internal_getConversationContext: log + fall back to global state when the op has been GC'd, instead of throwing. - submitHeteroIntervention: detect a stale opId before passing it into the optimistic chain. Scoped as a short-term backstop until LOBE-8746 retires the AskUser MCP bridge entirely. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat: support mpim * chore: add errorMsg * fix: discord commands thinking error * fix: discord typing error * feat: add oauth process for discord
… table (#14736) * ✨ feat(agent-runtime): persist agent operations to `agent_operations` table Wire start-time INSERT and terminal UPDATE into the agent runtime so operation history outlives the 2-hour Redis TTL. Adds `AgentOperationModel` with `recordStart` / `recordCompletion` / `findById` (scoped by userId so a leaked operationId can't flip another user's row) and threads both calls through `CompletionLifecycle`, which now owns both ends of the persistence lifecycle. Also plumbs `parentOperationId` through `ExecAgentParams` → `OperationCreationParams` so sub-agent invocations carry their parent lineage. Per-step aggregate updates are intentionally out of scope. Refs LOBE-8848 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 🐛 fix(agent-runtime): update CompletionLifecycle test constructor to 2 args CompletionLifecycle now constructs MessageModel internally from (db, userId), so the test builder passing a third messageModel arg tripped tsgo --noEmit. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a77234107e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| } catch { | ||
| // not staged — fall through to the disk-delete | ||
| } | ||
| await rm(path.resolve(dirPath, filePath), { force: true, recursive: false }); |
There was a problem hiding this comment.
Allow discarding untracked directories
When the dirty entry is an untracked directory, this discard path returns an error instead of removing it: I checked git status --porcelain -z in a temp repo and Git reports such entries as ?? newdir/\0, which this controller includes in the added-file list. Since rm(..., { recursive: false }) cannot remove directories, the UI's discard action will fail for the common case where a generated folder is untracked; use recursive removal for paths absent at HEAD or handle directories separately.
Useful? React with 👍 / 👎.
| // ends of the persistence lifecycle (start row here, terminal update | ||
| // in dispatchHooks) and swallows DB errors so runtime startup is never | ||
| // blocked. | ||
| await this.completionLifecycle.recordStart({ |
There was a problem hiding this comment.
Avoid recording operations before startup can abort
This writes a running agent_operations row before throwIfAborted and before the guarded startup block. If the signal is already aborted, or if coordinator.createAgentOperation / state save / first scheduling fails, the catch path never calls dispatchHooks and operationCreated only cleans up coordinator state, leaving a permanently running analytics row for an operation that never started. Move this persistence after startup succeeds or mark/delete the row in the failure paths.
Useful? React with 👍 / 👎.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #14739 +/- ##
==========================================
- Coverage 68.84% 65.80% -3.04%
==========================================
Files 2634 2943 +309
Lines 232067 257640 +25573
Branches 24593 31218 +6625
==========================================
+ Hits 159760 169533 +9773
- Misses 72157 87950 +15793
- Partials 150 157 +7
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
🐳 Database Docker Build Completed!Version: Pull ImageDownload the Docker image to your local machine: docker pull lobehub/lobehub:pr-hotfix-v2.1.57-ce08b9b1-dae2836Important This build is for testing and validation purposes. |
🚀 Desktop App Build Completed!Version: 📦 Release Download · 📥 Actions Artifacts Build Artifacts
Warning Note: This is a temporary build for testing purposes only. |
🚀 LobeHub Release (20260513)
Hotfix Scope: Ship the canary backlog (111 PRs) onto main as a fast-tracked patch — operator-focused, no weekly-style write-up.
✨ What's Included
lobe-agent, AskUserQuestion wiring for Claude Code, scheduler/hotkey/TodoList polish. (✨ feat(agent-signal,prompts,database): self-review now proposal actions to briefs, and automatically execute actions #14583, ✨ feat(agent-signal,server,prompts): consolidate in self-review implemented #14657, ♻️ refactor(builtin-tool): move sub-agent dispatch fromlobe-gtdtolobe-agent#14715, ✨ feat(hetero-agent): support AskUserQuestion tools for claude code #14639, 🐛 fix(hetero-agent): wire AskUserBridge response events to renderer #14732, 🐛 fix(tasks): scheduler, hotkey, comment & TodoList polish #14707, 🐛 fix(builtin-tool-task): expose lobe-task and add setTaskSchedule #14713)Exit code: 0tail #14596).cmdshim detection forclaude/codexCLIs, auth focus & pending-login reset fixes. (🐛 fix(desktop): detect Windows npm .cmd shims for CLI agents (claude/codex/…) #14720, 🐛 fix(desktop): focus onboarding auth success state #14694, 🐛 fix(desktop): reset pendingLoginMethod on auth failure/cancel paths #14695)agent_operationstable + persist agent operations from the runtime; switch user memory search toparadedb.match(...). (✨ feat(database): addagent_operationstable #14416, ✨ feat(agent-runtime): persist agent operations toagent_operationstable #14736, 🐛 fix(database,utils,userMemories): should perfer to useparadedb.match(...)instead of hardcoded normalizer #14590)⚙️ Upgrade
agent_operationstable) run automatically on boot.Full Changelog: v2.1.57...hotfix/v2.1.57-ce08b9b1