Skip to content

Conversation

@xinquiry
Copy link
Collaborator

@xinquiry xinquiry commented Jan 29, 2026

Summary

  • Fix beta workflow to use semantic version from pyproject.toml instead of timestamp-based version
  • Remove auto-update feature that caused infinite refresh loops
  • Fix broken JSX comment syntax in AgentList

Problem

In the test environment, the backend was showing beta-20260127111717-fed44e7 while the frontend showed 1.0.16. This version mismatch triggered the
auto-update hook, which attempted to refresh the page repeatedly, causing an infinite loop.

Changes

  1. Beta workflow (.github/workflows/beta.yaml): Extract version from service/pyproject.toml instead of generating a timestamp-based beta version
  2. Remove auto-update: Delete useAutoUpdate hook and UpdateOverlay component to prevent refresh loops
  3. Fix JSX comments: Convert // NOTE: to {/* NOTE: */} in AgentList.tsx

Test Plan

  • Deploy to test environment
  • Verify backend /xyzen/api/v1/system/version returns 1.0.16
  • Verify frontend loads without refresh loops

由 Sourcery 提供的摘要

使 beta 部署的版本管理与后端保持一致,并移除前端的自动更新行为,以防止刷新循环。

错误修复:

  • 将 beta 工作流版本与 pyproject.toml 中定义的服务语义版本对齐,避免前端/后端版本不匹配。
  • 移除自动更新钩子和覆盖层,使应用在测试环境中不再进入无限刷新循环。
  • 修复 AgentList 中无效的 JSX 注释语法,确保组件能够正确编译和渲染。

CI:

  • 更新 beta GitHub Actions 工作流,从 service/pyproject.toml 中读取版本号,而不是生成基于时间戳的 beta 版本。
Original summary in English

Summary by Sourcery

Align beta deployment versioning with backend and remove frontend auto-update behavior to prevent refresh loops.

Bug Fixes:

  • Align beta workflow version with service semantic version defined in pyproject.toml to avoid frontend/backend version mismatches.
  • Remove the auto-update hook and overlay so the app no longer enters an infinite refresh loop in test environments.
  • Fix invalid JSX comment syntax in AgentList to ensure the component compiles and renders correctly.

CI:

  • Update beta GitHub Actions workflow to read the version from service/pyproject.toml instead of generating a timestamp-based beta version.

  The auto-update mechanism causes infinite refresh loops when frontend
  and backend versions mismatch in test environment. Remove the feature
  entirely until a more robust solution is implemented.

  - Delete useAutoUpdate hook and UpdateOverlay component
  - Remove AutoUpdateWrapper from App.tsx
@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Jan 29, 2026

审阅者指南(在小型 PR 上折叠)

审阅者指南

通过更新 beta 构建工作流以从 pyproject.toml 读取语义化版本,使后端和前端版本保持一致,移除导致刷新循环的自动更新浮层逻辑,并修复 AgentList 中的 JSX 注释语法以恢复有效 JSX。

前端加载且无自动更新刷新循环的时序图

sequenceDiagram
  participant Browser
  participant XyzenApp
  participant BackendVersionAPI

  Browser->>XyzenApp: Load_application
  activate XyzenApp
  XyzenApp->>BackendVersionAPI: GET /xyzen/api/v1/system/version
  activate BackendVersionAPI
  BackendVersionAPI-->>XyzenApp: 200 { version: 1.0.16 }
  deactivate BackendVersionAPI
  XyzenApp-->>Browser: Render mainLayout without AutoUpdateWrapper
  deactivate XyzenApp
Loading

更新后应用结构及移除自动更新逻辑的类图

classDiagram
  class Xyzen {
    +Xyzen(props)
  }

  class AutoUpdateWrapper_removed {
    +AutoUpdateWrapper_removed(children)
  }

  class useAutoUpdate_removed {
    +useAutoUpdate_removed()
  }

  class UpdateOverlay_removed {
    +UpdateOverlay_removed(targetVersion)
  }

  Xyzen ..> AutoUpdateWrapper_removed : previously_wrapped_children
  AutoUpdateWrapper_removed ..> useAutoUpdate_removed : previously_called
  AutoUpdateWrapper_removed ..> UpdateOverlay_removed : previously_rendered
Loading

文件级变更

变更 详情 文件
更新 beta GitHub Actions 工作流,使其使用 service/pyproject.toml 中的语义化版本,而不是基于时间戳的 beta 版本字符串。
  • 使用 grep/sed 从 service/pyproject.toml 的 version 字段提取版本,替换基于时间戳的 beta_version 生成逻辑。
  • 保持其它工作流元数据输出(build_start、commit_* 字段)不变。
.github/workflows/beta.yaml
移除在版本不匹配时会触发无限刷新循环的前端自动更新机制。
  • 停止在 App.tsx 中使用 AutoUpdateWrapper 组件包裹主应用布局,改为直接渲染该布局。
  • 从 App.tsx 中删除 AutoUpdateWrapper 组件实现。
  • 从共享的特性导出索引中移除 UpdateOverlay。
  • 删除 UpdateOverlay 组件实现。
  • 删除 useAutoUpdate hook 实现。
web/src/app/App.tsx
web/src/components/features/index.ts
web/src/components/features/UpdateOverlay.tsx
web/src/hooks/useAutoUpdate.ts
修复 AgentList 中无效的 JSX 注释,以恢复正确的 JSX 解析,并保持拖拽浮层相关文档内联。
  • 将描述 DragOverlay 行为的行注释从 // NOTE 风格转换为使用 {/* ... */} 的 JSX 块注释。
  • 保留关于将 DragOverlay 渲染到 document.body 以及 CSS transforms 对 @dnd-kit 定位影响的说明。
web/src/components/agents/AgentList.tsx

技巧和命令

与 Sourcery 交互

  • 触发一次新的审阅: 在 pull request 上评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审阅评论。
  • 从审阅评论生成 GitHub issue: 回复 Sourcery 的某条审阅评论,请求创建一个 issue。你也可以在该审阅评论下回复 @sourcery-ai issue 来从这条评论创建 issue。
  • 生成 pull request 标题: 在 pull request 标题的任意位置写上 @sourcery-ai,即可随时生成标题。你也可以在 pull request 上评论 @sourcery-ai title,以在任意时间(重新)生成标题。
  • 生成 pull request 摘要: 在 pull request 正文的任意位置写上 @sourcery-ai summary,即可在你想要的位置生成 PR 摘要。你也可以在 pull request 上评论 @sourcery-ai summary,以在任意时间(重新)生成摘要。
  • 生成审阅者指南: 在 pull request 上评论 @sourcery-ai guide,即可在任意时间(重新)生成审阅者指南。
  • 解决所有 Sourcery 评论: 在 pull request 上评论 @sourcery-ai resolve,即可标记所有 Sourcery 评论为已解决。如果你已经处理完所有评论且不想再看到它们,这会很有用。
  • 忽略所有 Sourcery 审阅: 在 pull request 上评论 @sourcery-ai dismiss,即可忽略所有现有的 Sourcery 审阅。若你想用一次新的审阅重新开始,这尤其有用 —— 记得再评论 @sourcery-ai review 来触发新的审阅!

自定义你的体验

访问你的 控制面板 以:

  • 启用或禁用诸如 Sourcery 生成的 pull request 摘要、审阅者指南等审阅功能。
  • 更改审阅语言。
  • 添加、移除或编辑自定义审阅说明。
  • 调整其他审阅设置。

获取帮助

Original review guide in English
Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Aligns backend and frontend versions by updating the beta build workflow to read the semantic version from pyproject.toml, removes the auto-update overlay logic that caused refresh loops, and fixes JSX comment syntax in AgentList to restore valid JSX.

Sequence diagram for frontend load without auto-update refresh loop

sequenceDiagram
  participant Browser
  participant XyzenApp
  participant BackendVersionAPI

  Browser->>XyzenApp: Load_application
  activate XyzenApp
  XyzenApp->>BackendVersionAPI: GET /xyzen/api/v1/system/version
  activate BackendVersionAPI
  BackendVersionAPI-->>XyzenApp: 200 { version: 1.0.16 }
  deactivate BackendVersionAPI
  XyzenApp-->>Browser: Render mainLayout without AutoUpdateWrapper
  deactivate XyzenApp
Loading

Class diagram for updated app structure and removed auto-update logic

classDiagram
  class Xyzen {
    +Xyzen(props)
  }

  class AutoUpdateWrapper_removed {
    +AutoUpdateWrapper_removed(children)
  }

  class useAutoUpdate_removed {
    +useAutoUpdate_removed()
  }

  class UpdateOverlay_removed {
    +UpdateOverlay_removed(targetVersion)
  }

  Xyzen ..> AutoUpdateWrapper_removed : previously_wrapped_children
  AutoUpdateWrapper_removed ..> useAutoUpdate_removed : previously_called
  AutoUpdateWrapper_removed ..> UpdateOverlay_removed : previously_rendered
Loading

File-Level Changes

Change Details Files
Update beta GitHub Actions workflow to use semantic version from service/pyproject.toml instead of a timestamp-based beta version string.
  • Replace timestamp-based beta_version generation with grep/sed extraction of the version field from service/pyproject.toml.
  • Keep other workflow metadata outputs (build_start, commit_* fields) unchanged.
.github/workflows/beta.yaml
Remove frontend auto-update mechanism that was triggering infinite refresh loops on version mismatch.
  • Stop wrapping the main application layout with the AutoUpdateWrapper component in App.tsx, rendering the layout directly instead.
  • Delete the AutoUpdateWrapper component implementation from App.tsx.
  • Remove UpdateOverlay from the shared feature exports index.
  • Delete the UpdateOverlay component implementation.
  • Delete the useAutoUpdate hook implementation.
web/src/app/App.tsx
web/src/components/features/index.ts
web/src/components/features/UpdateOverlay.tsx
web/src/hooks/useAutoUpdate.ts
Fix invalid JSX comments in AgentList to restore proper JSX parsing and keep drag overlay documentation in-line.
  • Convert line comments describing DragOverlay behavior from // NOTE style to JSX block comments using {/* ... */}.
  • Preserve the explanation about rendering DragOverlay into document.body and the impact of CSS transforms on @dnd-kit positioning.
web/src/components/agents/AgentList.tsx

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我在这里给出了一些总体反馈:

  • .github/workflows/beta.yaml 中对 beta_version 的提取依赖于 service/pyproject.toml 里非常特定的 version = "..." 格式;建议让 grep/sed 更健壮一些(例如去除空白、处理单引号),或者在找不到该行时快速失败并给出清晰的错误信息。
  • 与其在 App.tsx 中完全移除自动更新流程,不如考虑用环境变量开关来控制,或者只在非生产环境中禁用它,这样以后就可以在不做结构性改动的前提下重新启用该功能。
给 AI Agent 的提示
Please address the comments from this code review:

## Overall Comments
- `.github/workflows/beta.yaml` 中对 `beta_version` 的提取依赖于 `service/pyproject.toml` 里非常特定的 `version = "..."` 格式;建议让 grep/sed 更健壮一些(例如去除空白、处理单引号),或者在找不到该行时快速失败并给出清晰的错误信息。
- 与其在 `App.tsx` 中完全移除自动更新流程,不如考虑用环境变量开关来控制,或者只在非生产环境中禁用它,这样以后就可以在不做结构性改动的前提下重新启用该功能。

Sourcery 对开源项目是免费的——如果你觉得我们的代码审查有帮助,欢迎分享 ✨
帮我变得更有用!请对每条评论点 👍 或 👎,我会根据你的反馈改进后续的代码审查。
Original comment in English

Hey - I've left some high level feedback:

  • The beta_version extraction in .github/workflows/beta.yaml assumes a very specific version = "..." format in service/pyproject.toml; consider making the grep/sed more robust (e.g., trimming whitespace, handling single quotes) or failing fast with a clear error if the line is not found.
  • Instead of fully removing the auto-update flow in App.tsx, you might want to gate it behind an environment flag or only disable it in non-production environments so the functionality can be re-enabled without a structural change later.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `beta_version` extraction in `.github/workflows/beta.yaml` assumes a very specific `version = "..."` format in `service/pyproject.toml`; consider making the grep/sed more robust (e.g., trimming whitespace, handling single quotes) or failing fast with a clear error if the line is not found.
- Instead of fully removing the auto-update flow in `App.tsx`, you might want to gate it behind an environment flag or only disable it in non-production environments so the functionality can be re-enabled without a structural change later.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@xinquiry xinquiry merged commit 4092960 into test Jan 29, 2026
2 checks passed
@xinquiry xinquiry deleted the fix/test-version branch January 29, 2026 05:14
Mile-Away added a commit that referenced this pull request Feb 1, 2026
* feat: add drag-and-drop agent reordering and auto-update on version mismatch (#206)

* fix: resolve i18next missing key warnings in TierInfoModal

Replace hardcoded Chinese strings with proper i18n translation keys
in the tier selector component. This fixes console warnings about
missing translation keys when using the zh locale.

- Add speedLabels, reasoningLabels, and features keys to app.json
- Add multiplier key to tierSelector in all locales
- Add recommended key to common.json in all locales
- Refactor TierInfoModal.tsx to use translation key references

Co-Authored-By: Claude <[email protected]>

* feat: add drag-and-drop agent reordering

   Integrate dnd-kit into existing AgentList and AgentListItem components
   to support drag-and-drop reordering in both the sidebar and spatial
   focused view.

   Backend:
   - Add sort_order field to Agent model
   - Add PATCH endpoint for bulk reordering agents
   - Add migration for sort_order column

   Frontend:
   - Add sortable prop to AgentList with DndContext/SortableContext
   - Add dragHandleProps to AgentListItem for drag behavior
   - Use plain div (not motion.div) when sortable to avoid animation conflicts
   - Use set-based comparison for state sync (only reset on add/remove)
   - Add reorderAgents action to agentSlice

* feat: auto-refresh frontend on version mismatch with backend

  Add automatic update mechanism that detects when the frontend version
  doesn't match the backend version and refreshes the page to fetch the
  latest assets. This ensures users with cached frontends always get
  updated code without manually clearing their browser cache.

  - Add useAutoUpdate hook with retry logic (max 3 attempts)
  - Add UpdateOverlay component for update feedback
  - Clear service workers and caches before reload
  - Store retry state in localStorage to prevent infinite loops

* fix: address PR review feedback for drag-and-drop agent reordering

  - Move AgentList state sync from render to useEffect to prevent render loops
  - Add isDraggingRef to prevent backend sync during active drag operations
  - Restore keyboard accessibility to CompactAgentListItem (role, tabIndex,
    aria-pressed, onKeyDown handler)
  - Guard localStorage writes with try/catch in useAutoUpdate to handle
    restricted environments

---------

Co-authored-by: Claude <[email protected]>

* fix: resolve version mismatch causing refresh loops in test environment (#207)

* fix: move the comment to correct position

* fix: fix the test environment version

* fix: remove auto-update feature to prevent refresh loops

  The auto-update mechanism causes infinite refresh loops when frontend
  and backend versions mismatch in test environment. Remove the feature
  entirely until a more robust solution is implemented.

  - Delete useAutoUpdate hook and UpdateOverlay component
  - Remove AutoUpdateWrapper from App.tsx

* Fix: Unify tool call UI (pills in agent timeline) for streaming + refresh (#208)

* feat: add simple landing page and logout button

* fix(web): unify tool call rendering in agent timeline after refresh; add landing page

  - Render tool calls as pills with a shared details modal (args/results/errors)
  - Attach historical tool_call tool messages into agentExecution phases instead of standalone messages
  - Remove legacy ToolCallCard-based rendering path

* fix(web): address review feedback for tool call modal + typewriter

  - Move tool-call UI strings into i18n (app.chat.toolCall.*) for en/zh/ja
  - Memoize tool result parsing and image URL derivation in ToolCallDetails
  - Avoid duplicate argument headings in ToolCallDetailsModal for waiting_confirmation
  - Remove redundant typewriter cursor className conditional and fix unused state var

* feat: message editing and deletion (#209)

* feat: add message editing and deletion with truncate-regenerate flow

  - Add PATCH /messages/{id} endpoint for editing user messages
  - Add DELETE /messages/{id} endpoint for deleting any message
  - Add regenerate WebSocket handler for re-running agent after edit
  - Add edit/delete UI to ChatBubble with hover actions
  - Add i18n translations for en/zh/ja

  Includes fixes from code review:
  - Fix pre-deduction error handling to skip dispatch on any failure
  - Reset responding state before regeneration to prevent stuck UI
  - Add message ownership verification before edit/delete operations

* fix: improve the code according to sourcery review

* fix: use version+SHA for beta image tags to ensure unique deployments (#211)

The previous approach used only the pyproject.toml version (e.g., 1.0.16)
which caused Kubernetes to not pull new images when multiple commits
used the same version tag.

Now uses format: {version}-{short-sha} (e.g., 1.0.16-f13e3c0)

Co-authored-by: Claude (Vendor2/Claude-4.5-Opus) <[email protected]>

* feat: conversation interrupt/abort functionality (#212)

* feat: add conversation interrupt/abort functionality

- Add stop button and Escape key shortcut to abort streaming generation
- Implement Redis-based signaling between API server and Celery worker
- Worker checks abort signal every 0.5s and gracefully stops streaming
- Save partial content and perform partial billing on abort
- Add visual indicator for cancelled/aborted messages
- Add timeout fallback (10s) to reset UI if backend doesn't respond
- Add i18n strings for stop/stopping/escToStop in en/zh/ja

* fix: address abort feature edge cases from code review

- Clear stale abort signals at task start to prevent race condition when
  user reconnects quickly after disconnect
- Finalize AgentRun with 'failed' status on unhandled exceptions to ensure
  consistent DB state across all exit paths
- Move time import to module level (was inline import)

* fix: address Sourcery review feedback for abort feature

- Reuse existing Redis client for abort checks instead of creating new
  connections on each tick (performance improvement)
- Fix potential Redis connection leaks in ABORT and disconnect handlers
  by using try/finally pattern
- Track and cleanup abort timeout in frontend to prevent stale timers
  from racing with subsequent abort requests

* Preserve phase text when copying streamed output (#210)

* Preserve phase text when copying streamed output

* Extract agent phase content helper

* fix: use existing PhaseExecution type and correct useMemo dependencies

- Replace inline PhaseWithStreamedContent type with Pick<PhaseExecution, 'streamedContent'>
  for type consistency across the codebase
- Fix useMemo dependency array to use agentExecution?.phases instead of agentExecution
  to ensure proper recalculation when phases array changes

* Fix streaming agent messages and prevent deleting non-persisted messages (#213)

* Fix message deletion for agent executions

* Address Sourcery review: stricter UUID validation and safer id assignment

- Add isValidUuid utility with canonical UUID pattern (8-4-4-4-12 format)
  to replace loose regex that accepted invalid strings like all-hyphens
- Fix streaming_start handler to only set id when eventData.id is truthy,
  preventing accidental overwrites with undefined/null
- Improve delete guard with contextual messages ("still streaming" vs
  "not saved yet") and change notification type to warning
- Add comprehensive tests for isValidUuid covering valid UUIDs, client IDs,
  invalid formats, and edge cases

Co-Authored-By: Claude (Vendor2/Claude-4.5-Opus) <[email protected]>

---------

Co-authored-by: Claude (Vendor2/Claude-4.5-Opus) <[email protected]>

* fix: emit message_saved event after stream abort (#215)

* fix: emit message_saved event after stream abort

When a user interrupts a streaming response, the message is saved to the
database but the frontend never receives the message_saved event. This
leaves the message with a temporary stream_ prefix ID, preventing deletion
until page refresh.

Now the MESSAGE_SAVED event is emitted after db.commit() in the abort
handler, before STREAM_ABORTED, so the frontend updates the message ID
to the real UUID and deletion works immediately.

Co-Authored-By: Claude (Vendor2/Claude-4.5-Opus) <[email protected]>

* fix: always show latest topic when clicking an agent

Unify sidebar and spatial workspace to use the same logic for selecting
topics. Both now fetch from backend and always show the most recently
updated topic (by updated_at) instead of remembering previously active topics.

Co-Authored-By: Claude (Vendor2/Claude-4.5-Opus) <[email protected]>

* feat: improve message editing UX with edit-only option and assistant editing

- Add "Edit" and "Edit & Regenerate" dropdown options for user messages
- Allow editing assistant messages (content-only, no regeneration)
- Add copy button to user messages
- Move assistant message actions to top-right for better UX
- Add auto-resizing textarea for editing long messages
- Update backend to support truncate_and_regenerate flag

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* refactor: extract message content resolution into dedicated module

Extract scattered content resolution logic into core/chat/messageContent.ts
with two main utilities:
- resolveMessageContent(): Single source of truth for content priority
- getMessageDisplayMode(): Explicit rendering mode determination

This refactoring:
- Reduces ChatBubble.tsx complexity (60+ line IIFE → 30 line switch)
- Fixes inconsistency between copy/edit and display logic
- Makes content source priority explicit and documented
- Adds guard for empty content to avoid rendering empty divs
- Improves maintainability with testable pure functions

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude (Vendor2/Claude-4.5-Opus) <[email protected]>

* fix: deep research structured output and recursion limit (#216)

- Use function_calling method for structured output in clarify node.
  The default json_mode doesn't work with Claude models via GPUGEEK
  provider. Claude supports tool/function calling natively but not
  OpenAI's response_format JSON mode.

- Increase recursion_limit from 25 to 50 in agent.astream() to handle
  complex research tasks with more iterations.

Co-authored-by: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: xinquiry(SII) <[email protected]>
Co-authored-by: Claude <[email protected]>
xinquiry added a commit that referenced this pull request Feb 1, 2026
* feat: add drag-and-drop agent reordering and auto-update on version mismatch (#206)

* fix: resolve i18next missing key warnings in TierInfoModal

Replace hardcoded Chinese strings with proper i18n translation keys
in the tier selector component. This fixes console warnings about
missing translation keys when using the zh locale.

- Add speedLabels, reasoningLabels, and features keys to app.json
- Add multiplier key to tierSelector in all locales
- Add recommended key to common.json in all locales
- Refactor TierInfoModal.tsx to use translation key references

Co-Authored-By: Claude <[email protected]>

* feat: add drag-and-drop agent reordering

   Integrate dnd-kit into existing AgentList and AgentListItem components
   to support drag-and-drop reordering in both the sidebar and spatial
   focused view.

   Backend:
   - Add sort_order field to Agent model
   - Add PATCH endpoint for bulk reordering agents
   - Add migration for sort_order column

   Frontend:
   - Add sortable prop to AgentList with DndContext/SortableContext
   - Add dragHandleProps to AgentListItem for drag behavior
   - Use plain div (not motion.div) when sortable to avoid animation conflicts
   - Use set-based comparison for state sync (only reset on add/remove)
   - Add reorderAgents action to agentSlice

* feat: auto-refresh frontend on version mismatch with backend

  Add automatic update mechanism that detects when the frontend version
  doesn't match the backend version and refreshes the page to fetch the
  latest assets. This ensures users with cached frontends always get
  updated code without manually clearing their browser cache.

  - Add useAutoUpdate hook with retry logic (max 3 attempts)
  - Add UpdateOverlay component for update feedback
  - Clear service workers and caches before reload
  - Store retry state in localStorage to prevent infinite loops

* fix: address PR review feedback for drag-and-drop agent reordering

  - Move AgentList state sync from render to useEffect to prevent render loops
  - Add isDraggingRef to prevent backend sync during active drag operations
  - Restore keyboard accessibility to CompactAgentListItem (role, tabIndex,
    aria-pressed, onKeyDown handler)
  - Guard localStorage writes with try/catch in useAutoUpdate to handle
    restricted environments

---------

Co-authored-by: Claude <[email protected]>

* fix: resolve version mismatch causing refresh loops in test environment (#207)

* fix: move the comment to correct position

* fix: fix the test environment version

* fix: remove auto-update feature to prevent refresh loops

  The auto-update mechanism causes infinite refresh loops when frontend
  and backend versions mismatch in test environment. Remove the feature
  entirely until a more robust solution is implemented.

  - Delete useAutoUpdate hook and UpdateOverlay component
  - Remove AutoUpdateWrapper from App.tsx

* Fix: Unify tool call UI (pills in agent timeline) for streaming + refresh (#208)

* feat: add simple landing page and logout button

* fix(web): unify tool call rendering in agent timeline after refresh; add landing page

  - Render tool calls as pills with a shared details modal (args/results/errors)
  - Attach historical tool_call tool messages into agentExecution phases instead of standalone messages
  - Remove legacy ToolCallCard-based rendering path

* fix(web): address review feedback for tool call modal + typewriter

  - Move tool-call UI strings into i18n (app.chat.toolCall.*) for en/zh/ja
  - Memoize tool result parsing and image URL derivation in ToolCallDetails
  - Avoid duplicate argument headings in ToolCallDetailsModal for waiting_confirmation
  - Remove redundant typewriter cursor className conditional and fix unused state var

* feat: message editing and deletion (#209)

* feat: add message editing and deletion with truncate-regenerate flow

  - Add PATCH /messages/{id} endpoint for editing user messages
  - Add DELETE /messages/{id} endpoint for deleting any message
  - Add regenerate WebSocket handler for re-running agent after edit
  - Add edit/delete UI to ChatBubble with hover actions
  - Add i18n translations for en/zh/ja

  Includes fixes from code review:
  - Fix pre-deduction error handling to skip dispatch on any failure
  - Reset responding state before regeneration to prevent stuck UI
  - Add message ownership verification before edit/delete operations

* fix: improve the code according to sourcery review

* fix: use version+SHA for beta image tags to ensure unique deployments (#211)

The previous approach used only the pyproject.toml version (e.g., 1.0.16)
which caused Kubernetes to not pull new images when multiple commits
used the same version tag.

Now uses format: {version}-{short-sha} (e.g., 1.0.16-f13e3c0)

Co-authored-by: Claude (Vendor2/Claude-4.5-Opus) <[email protected]>

* feat: conversation interrupt/abort functionality (#212)

* feat: add conversation interrupt/abort functionality

- Add stop button and Escape key shortcut to abort streaming generation
- Implement Redis-based signaling between API server and Celery worker
- Worker checks abort signal every 0.5s and gracefully stops streaming
- Save partial content and perform partial billing on abort
- Add visual indicator for cancelled/aborted messages
- Add timeout fallback (10s) to reset UI if backend doesn't respond
- Add i18n strings for stop/stopping/escToStop in en/zh/ja

* fix: address abort feature edge cases from code review

- Clear stale abort signals at task start to prevent race condition when
  user reconnects quickly after disconnect
- Finalize AgentRun with 'failed' status on unhandled exceptions to ensure
  consistent DB state across all exit paths
- Move time import to module level (was inline import)

* fix: address Sourcery review feedback for abort feature

- Reuse existing Redis client for abort checks instead of creating new
  connections on each tick (performance improvement)
- Fix potential Redis connection leaks in ABORT and disconnect handlers
  by using try/finally pattern
- Track and cleanup abort timeout in frontend to prevent stale timers
  from racing with subsequent abort requests

* Preserve phase text when copying streamed output (#210)

* Preserve phase text when copying streamed output

* Extract agent phase content helper

* fix: use existing PhaseExecution type and correct useMemo dependencies

- Replace inline PhaseWithStreamedContent type with Pick<PhaseExecution, 'streamedContent'>
  for type consistency across the codebase
- Fix useMemo dependency array to use agentExecution?.phases instead of agentExecution
  to ensure proper recalculation when phases array changes

* Fix streaming agent messages and prevent deleting non-persisted messages (#213)

* Fix message deletion for agent executions

* Address Sourcery review: stricter UUID validation and safer id assignment

- Add isValidUuid utility with canonical UUID pattern (8-4-4-4-12 format)
  to replace loose regex that accepted invalid strings like all-hyphens
- Fix streaming_start handler to only set id when eventData.id is truthy,
  preventing accidental overwrites with undefined/null
- Improve delete guard with contextual messages ("still streaming" vs
  "not saved yet") and change notification type to warning
- Add comprehensive tests for isValidUuid covering valid UUIDs, client IDs,
  invalid formats, and edge cases

Co-Authored-By: Claude (Vendor2/Claude-4.5-Opus) <[email protected]>

---------

Co-authored-by: Claude (Vendor2/Claude-4.5-Opus) <[email protected]>

* fix: emit message_saved event after stream abort (#215)

* fix: emit message_saved event after stream abort

When a user interrupts a streaming response, the message is saved to the
database but the frontend never receives the message_saved event. This
leaves the message with a temporary stream_ prefix ID, preventing deletion
until page refresh.

Now the MESSAGE_SAVED event is emitted after db.commit() in the abort
handler, before STREAM_ABORTED, so the frontend updates the message ID
to the real UUID and deletion works immediately.

Co-Authored-By: Claude (Vendor2/Claude-4.5-Opus) <[email protected]>

* fix: always show latest topic when clicking an agent

Unify sidebar and spatial workspace to use the same logic for selecting
topics. Both now fetch from backend and always show the most recently
updated topic (by updated_at) instead of remembering previously active topics.

Co-Authored-By: Claude (Vendor2/Claude-4.5-Opus) <[email protected]>

* feat: improve message editing UX with edit-only option and assistant editing

- Add "Edit" and "Edit & Regenerate" dropdown options for user messages
- Allow editing assistant messages (content-only, no regeneration)
- Add copy button to user messages
- Move assistant message actions to top-right for better UX
- Add auto-resizing textarea for editing long messages
- Update backend to support truncate_and_regenerate flag

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* refactor: extract message content resolution into dedicated module

Extract scattered content resolution logic into core/chat/messageContent.ts
with two main utilities:
- resolveMessageContent(): Single source of truth for content priority
- getMessageDisplayMode(): Explicit rendering mode determination

This refactoring:
- Reduces ChatBubble.tsx complexity (60+ line IIFE → 30 line switch)
- Fixes inconsistency between copy/edit and display logic
- Makes content source priority explicit and documented
- Adds guard for empty content to avoid rendering empty divs
- Improves maintainability with testable pure functions

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude (Vendor2/Claude-4.5-Opus) <[email protected]>

* fix: deep research structured output and recursion limit (#216)

- Use function_calling method for structured output in clarify node.
  The default json_mode doesn't work with Claude models via GPUGEEK
  provider. Claude supports tool/function calling natively but not
  OpenAI's response_format JSON mode.

- Increase recursion_limit from 25 to 50 in agent.astream() to handle
  complex research tasks with more iterations.

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix: attach thinking content to agent execution message

When agent_start event arrives before thinking_start, it consumes the
loading message. The thinking_start handler then couldn't find a loading
message and created a separate thinking message, causing the thinking
content to appear as a separate bubble below the agent response.

Fix the thinking event handlers to also check for running agent execution
messages and attach thinking content to them instead of creating separate
messages.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: align thinking_end condition with thinking_chunk

Use consistent condition `m.agentExecution?.status === "running"` in both
thinking_chunk and thinking_end handlers for finding agent messages.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants