Repository navigation
Feature/knowledge document read - #888
Conversation
📝 WalkthroughWalkthroughThe changes introduce pagination-based document content reading across the backend by adding Changes
Sequence DiagramsequenceDiagram
participant Client
participant Endpoint as API Endpoint<br/>(/detail)
participant Orchestrator
participant AccessCheck as Access Validation
participant Reader as Document Read<br/>Service
participant DB as Database
Client->>Endpoint: GET /api/knowledge-documents/{id}/detail
activate Endpoint
Endpoint->>Orchestrator: get_document_detail(document_id,<br/>include_content, include_summary,<br/>offset, limit)
activate Orchestrator
Orchestrator->>AccessCheck: Validate user access & KB existence
activate AccessCheck
AccessCheck->>DB: Query KnowledgeDocument & KB
DB-->>AccessCheck: Document + KB
AccessCheck-->>Orchestrator: Access granted
deactivate AccessCheck
alt include_content=True
Orchestrator->>Reader: read_documents(document_id,<br/>offset, limit)
activate Reader
Reader->>DB: Fetch document content slice
DB-->>Reader: Content + pagination metadata
Reader-->>Orchestrator: DocumentContentReadResponse
deactivate Reader
end
alt include_summary=True
Orchestrator->>Orchestrator: get_document_summary(document_id)
Orchestrator-->>Orchestrator: Fetch/normalize summary
end
Orchestrator-->>Endpoint: DocumentDetailResponse<br/>(content, summary, metadata)
deactivate Orchestrator
Endpoint-->>Client: HTTP 200 + JSON detail
deactivate Endpoint
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (5)
backend/tests/mcp_server/test_tools.py (1)
241-246: Assert the default limit semantically, not via source text.
inspect.getsource()on a decorated tool is brittle and may inspect the wrapper rather than the underlying function. Comparing the callable's default value againstMAX_DOCUMENT_READ_LIMITmakes the test stable and checks the behavior you actually care about.♻️ Suggested test shape
- source = inspect.getsource(module.read_document_content) - assert "limit: int = 100000" not in source + target = getattr( + module.read_document_content, + "__wrapped__", + module.read_document_content, + ) + default_limit = inspect.signature(target).parameters["limit"].default + assert default_limit == module.MAX_DOCUMENT_READ_LIMIT🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/tests/mcp_server/test_tools.py` around lines 241 - 246, The test is brittle because it inspects source text of the decorated read_document_content; instead assert the function's default limit equals the shared MAX_DOCUMENT_READ_LIMIT constant. Retrieve the callable from get_knowledge_module(), unwrap if needed (e.g., via getattr(func, "__wrapped__", func)), use inspect.signature(func).parameters["limit"].default (or func.__defaults__) and assert it equals MAX_DOCUMENT_READ_LIMIT to verify the semantic default value for read_document_content.backend/app/api/endpoints/knowledge.py (1)
64-125: Extract the detail helpers into a smaller module.This file is already well past the repo's 1000-line cap, and the new
/detailhelpers are a clean seam for pulling document-detail logic into its own module without changing behavior.As per coding guidelines, "File size limit: If a file exceeds 1000 lines, split it into multiple sub-modules".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/app/api/endpoints/knowledge.py` around lines 64 - 125, Extract the three helper functions _serialize_standalone_document_detail, _raise_document_detail_http_error, and _validate_knowledge_base_access_or_raise into a new small module (preserving their exact signatures and docstrings) and import them back into this file where they are used so behavior doesn't change; when moving, also move or import their dependencies (Session, User, KnowledgeService, HTTPException, status) into the new module and ensure no circular imports are introduced, then update this file's imports to reference the new module and run tests to confirm behavior remains identical.backend/app/services/knowledge/orchestrator.py (2)
688-798: Extract and trace this new read/detail path.These additions keep growing an already oversized module, and the new public entrypoints still skip the repo’s OpenTelemetry tracing convention. Moving this flow into a small dedicated submodule and adding
@trace_sync/@trace_asyncthere would make it easier to evolve and observe.As per coding guidelines "File size limit: If a file exceeds 1000 lines, split it into multiple sub-modules" and "Use
@trace_async(span_name, tracer_name, extract_attributes)decorator to trace entire async functions in OpenTelemetry" / "Use@trace_sync(span_name, tracer_name, extract_attributes)decorator to trace entire sync functions in OpenTelemetry".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/app/services/knowledge/orchestrator.py` around lines 688 - 798, The new public entrypoints read_document_content and get_document_detail were added into an already large module and lack OpenTelemetry tracing; move their implementation into a small new submodule (e.g., services/knowledge/document_reading.py) and import them from orchestrator to keep file size down, then annotate the sync read_document_content with `@trace_sync` and the async get_document_detail with `@trace_async` using appropriate span names (e.g., "knowledge.read_document_content"/"knowledge.get_document_detail"), tracer name, and an extract_attributes function that captures document_id, user id, offset, and limit; ensure the orchestrator retains the same function signatures but delegates to the traced functions in the new submodule so callers are unchanged.
729-732: Avoid mapping reader failures from raw error text.This 404 path depends on the exact
"Document not found"wording coming back fromdocument_read_service. A shared error code/constant would make the API behavior stable if the reader message changes.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/app/services/knowledge/orchestrator.py` around lines 729 - 732, The current check in orchestrator.py that treats result.get("error") == "Document not found" is brittle; update the contract with document_read_service to return a stable error indicator (e.g., an error_code or raise a specific exception) and then change the logic in the orchestrator handling (the block that inspects result and raises ValueError) to check that stable indicator instead of raw text; for example, have document_read_service return {'error': '...', 'error_code': 'DOCUMENT_NOT_FOUND'} or raise DocumentNotFoundError, and in the orchestrator replace the string comparison with a check against the error_code constant (DOCUMENT_NOT_FOUND) or catch DocumentNotFoundError, then raise ValueError("Document not found") as before.backend/tests/api/endpoints/test_knowledge_document_detail_endpoints.py (1)
16-40: Assert the forwarded orchestrator kwargs, not just that the mock was awaited.These tests would still pass if the endpoint stopped propagating
document_id,include_content,include_summary,offset, orlimitcorrectly. Since pagination is the feature being introduced here, please inspectmock_detail.await_args.kwargsor useassert_awaited_once_with(...).🧪 Example tightening for one happy-path case
with patch( "app.api.endpoints.knowledge.knowledge_orchestrator.get_document_detail", new_callable=AsyncMock, return_value=payload, ) as mock_detail: response = test_client.get( "/api/knowledge-documents/9/detail", + params={"offset": 10, "limit": 20}, headers=_auth_header(test_token), ) assert response.status_code == 200 assert response.json() == payload mock_detail.assert_awaited_once() + kwargs = mock_detail.await_args.kwargs + assert kwargs["document_id"] == 9 + assert kwargs["offset"] == 10 + assert kwargs["limit"] == 20Also applies to: 43-86, 107-135
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/tests/api/endpoints/test_knowledge_document_detail_endpoints.py` around lines 16 - 40, The test currently only verifies get_document_detail was awaited; update test_standalone_detail_uses_orchestrator to assert the orchestrator received the expected kwargs (document_id, include_content, include_summary, offset, limit) by either using mock_detail.assert_awaited_once_with(...) with the expected argument values or by inspecting mock_detail.await_args.kwargs and comparing to the expected dict (e.g., document_id=9 and the default include_content/include_summary/offset/limit values your endpoint should forward) so the endpoint's propagation of pagination and include flags is covered.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@backend/app/api/endpoints/knowledge.py`:
- Around line 776-790: The current handler returns a 200 for requests with
include_content=false and include_summary=false because access checks are only
done inside KnowledgeOrchestrator.get_document_detail when one of those flags is
true; fix by forcing a preflight access check: if not include_content and not
include_summary, call knowledge_orchestrator.get_document_detail(db=db,
user=current_user, document_id=document_id, include_content=True,
include_summary=False) inside the same try/except (so ValueError still maps via
_raise_document_detail_http_error), then discard content/summary and return the
minimal serialized response via _serialize_standalone_document_detail; this
preserves authorization/404 behavior while keeping the response body limited
when both flags are false.
In `@backend/app/schemas/knowledge.py`:
- Around line 578-580: Add non-negative validation to the paging metadata by
tightening the Pydantic Field definitions for total_length, offset, and
returned_length: update their Field(...) declarations to enforce a minimum of 0
(e.g., using ge=0 or a conint with ge=0) and keep the existing descriptions, so
any incoming payload with negative values fails validation immediately; locate
the fields named total_length, offset, and returned_length in the relevant
Pydantic model and apply the ge=0 constraint to each Field.
In `@backend/app/services/knowledge/orchestrator.py`:
- Around line 762-767: The access check is skipped when both include_content and
include_summary are false, allowing DocumentDetailResponse to be returned for
arbitrary document_id; ensure you always call
self._get_document_with_access_or_raise(db=db, user=user,
document_id=document_id) before building/returning the DocumentDetailResponse
(i.e., move the access validation out of the include_content/include_summary
conditional so access is validated unconditionally).
In `@backend/init_data/skills/wegent-knowledge/SKILL.md`:
- Around line 116-121: The unlabeled fenced code block containing the example
call to read_document_content(document_id=456, offset=0) needs a language tag to
satisfy markdownlint; update the triple-backtick fence around that example in
SKILL.md to include a language identifier (e.g., text) so the block reads
```text ... ``` and the lint error is resolved.
In
`@docs/superpowers/plans/2026-03-30-wegent-knowledge-document-read-implementation.md`:
- Around line 1-5: The docs file is missing required YAML frontmatter with a
sidebar_position which breaks ordering; add a YAML frontmatter block at the very
top of the document (between --- markers) that includes at minimum a numeric
sidebar_position key (e.g., sidebar_position: 30) and any other standard
frontmatter fields you want (title, description) so the page sorts correctly;
ensure the frontmatter precedes the existing content and retains the document
title and body unchanged.
---
Nitpick comments:
In `@backend/app/api/endpoints/knowledge.py`:
- Around line 64-125: Extract the three helper functions
_serialize_standalone_document_detail, _raise_document_detail_http_error, and
_validate_knowledge_base_access_or_raise into a new small module (preserving
their exact signatures and docstrings) and import them back into this file where
they are used so behavior doesn't change; when moving, also move or import their
dependencies (Session, User, KnowledgeService, HTTPException, status) into the
new module and ensure no circular imports are introduced, then update this
file's imports to reference the new module and run tests to confirm behavior
remains identical.
In `@backend/app/services/knowledge/orchestrator.py`:
- Around line 688-798: The new public entrypoints read_document_content and
get_document_detail were added into an already large module and lack
OpenTelemetry tracing; move their implementation into a small new submodule
(e.g., services/knowledge/document_reading.py) and import them from orchestrator
to keep file size down, then annotate the sync read_document_content with
`@trace_sync` and the async get_document_detail with `@trace_async` using
appropriate span names (e.g.,
"knowledge.read_document_content"/"knowledge.get_document_detail"), tracer name,
and an extract_attributes function that captures document_id, user id, offset,
and limit; ensure the orchestrator retains the same function signatures but
delegates to the traced functions in the new submodule so callers are unchanged.
- Around line 729-732: The current check in orchestrator.py that treats
result.get("error") == "Document not found" is brittle; update the contract with
document_read_service to return a stable error indicator (e.g., an error_code or
raise a specific exception) and then change the logic in the orchestrator
handling (the block that inspects result and raises ValueError) to check that
stable indicator instead of raw text; for example, have document_read_service
return {'error': '...', 'error_code': 'DOCUMENT_NOT_FOUND'} or raise
DocumentNotFoundError, and in the orchestrator replace the string comparison
with a check against the error_code constant (DOCUMENT_NOT_FOUND) or catch
DocumentNotFoundError, then raise ValueError("Document not found") as before.
In `@backend/tests/api/endpoints/test_knowledge_document_detail_endpoints.py`:
- Around line 16-40: The test currently only verifies get_document_detail was
awaited; update test_standalone_detail_uses_orchestrator to assert the
orchestrator received the expected kwargs (document_id, include_content,
include_summary, offset, limit) by either using
mock_detail.assert_awaited_once_with(...) with the expected argument values or
by inspecting mock_detail.await_args.kwargs and comparing to the expected dict
(e.g., document_id=9 and the default
include_content/include_summary/offset/limit values your endpoint should
forward) so the endpoint's propagation of pagination and include flags is
covered.
In `@backend/tests/mcp_server/test_tools.py`:
- Around line 241-246: The test is brittle because it inspects source text of
the decorated read_document_content; instead assert the function's default limit
equals the shared MAX_DOCUMENT_READ_LIMIT constant. Retrieve the callable from
get_knowledge_module(), unwrap if needed (e.g., via getattr(func, "__wrapped__",
func)), use inspect.signature(func).parameters["limit"].default (or
func.__defaults__) and assert it equals MAX_DOCUMENT_READ_LIMIT to verify the
semantic default value for read_document_content.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 5de4effc-3974-484d-8921-b7f6dc387d03
📒 Files selected for processing (11)
.gitignorebackend/app/api/endpoints/knowledge.pybackend/app/mcp_server/tools/knowledge.pybackend/app/schemas/knowledge.pybackend/app/services/knowledge/orchestrator.pybackend/init_data/skills/wegent-knowledge/SKILL.mdbackend/tests/api/endpoints/test_knowledge_document_detail_endpoints.pybackend/tests/mcp_server/test_tools.pybackend/tests/services/knowledge/test_orchestrator.pydocs/superpowers/plans/2026-03-30-wegent-knowledge-document-read-implementation.mddocs/superpowers/specs/2026-03-30-wegent-knowledge-document-read-design.md
| try: | ||
| detail = await knowledge_orchestrator.get_document_detail( | ||
| db=db, | ||
| user=current_user, | ||
| document_id=document_id, | ||
| include_content=include_content, | ||
| include_summary=include_summary, | ||
| ) | ||
| if not has_access: | ||
| raise HTTPException( | ||
| status_code=status.HTTP_403_FORBIDDEN, | ||
| detail="Access denied to this document", | ||
| return _serialize_standalone_document_detail( | ||
| detail, | ||
| include_content=include_content, | ||
| include_summary=include_summary, | ||
| ) | ||
|
|
||
| # Get content if requested | ||
| content = None | ||
| content_length = None | ||
| truncated = False | ||
|
|
||
| if include_content and document.attachment_id: | ||
| try: | ||
| from app.services.context import context_service | ||
|
|
||
| attachment = context_service.get_context_by_id( | ||
| db=db, | ||
| context_id=document.attachment_id, | ||
| ) | ||
| if attachment and attachment.extracted_text: | ||
| full_content = attachment.extracted_text | ||
| content_length = len(full_content) | ||
| # Truncate if too large | ||
| max_length = 100000 | ||
| if content_length > max_length: | ||
| content = full_content[:max_length] | ||
| truncated = True | ||
| else: | ||
| content = full_content | ||
| except Exception as e: | ||
| logger.warning(f"Failed to get document content: {e}") | ||
|
|
||
| # Build response | ||
| response = { | ||
| "document_id": document_id, | ||
| } | ||
|
|
||
| if include_content: | ||
| response["content"] = content | ||
| response["content_length"] = content_length | ||
| response["truncated"] = truncated | ||
|
|
||
| if include_summary: | ||
| response["summary"] = document.summary | ||
|
|
||
| return response | ||
| except ValueError as error: | ||
| _raise_document_detail_http_error(error) |
There was a problem hiding this comment.
Preserve 404/403 checks when both include flags are false.
KnowledgeOrchestrator.get_document_detail() only performs document access validation when include_content or include_summary is true. With the current delegation, GET /{document_id}/detail?include_content=false&include_summary=false now returns {"document_id": ...} with HTTP 200 even for missing or unauthorized documents. Please either reject that parameter combination or force a preflight access check before returning the bare ID.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@backend/app/api/endpoints/knowledge.py` around lines 776 - 790, The current
handler returns a 200 for requests with include_content=false and
include_summary=false because access checks are only done inside
KnowledgeOrchestrator.get_document_detail when one of those flags is true; fix
by forcing a preflight access check: if not include_content and not
include_summary, call knowledge_orchestrator.get_document_detail(db=db,
user=current_user, document_id=document_id, include_content=True,
include_summary=False) inside the same try/except (so ValueError still maps via
_raise_document_detail_http_error), then discard content/summary and return the
minimal serialized response via _serialize_standalone_document_detail; this
preserves authorization/404 behavior while keeping the response body limited
when both flags are false.
| # Wegent Knowledge Document Read Implementation Plan | ||
|
|
||
| > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. | ||
|
|
||
| **Goal:** Add a single-document content read capability to the Wegent Knowledge Base MCP skill, unify document-read logic through `KnowledgeOrchestrator`, and refactor existing REST `/detail` endpoints to reuse the unified read/detail flow without changing their public response shape. |
There was a problem hiding this comment.
Add docs frontmatter before merging this file.
Pages under docs/ need a sidebar_position frontmatter block; without it this page will not sort correctly in the generated docs.
As per coding guidelines, "All documentation files MUST include frontmatter with sidebar_position for ordering".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@docs/superpowers/plans/2026-03-30-wegent-knowledge-document-read-implementation.md`
around lines 1 - 5, The docs file is missing required YAML frontmatter with a
sidebar_position which breaks ordering; add a YAML frontmatter block at the very
top of the document (between --- markers) that includes at minimum a numeric
sidebar_position key (e.g., sidebar_position: 30) and any other standard
frontmatter fields you want (title, description) so the page sorts correctly;
ensure the frontmatter precedes the existing content and retains the document
title and body unchanged.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
backend/app/api/endpoints/internal/rag.py (1)
721-726: 🛠️ Refactor suggestion | 🟠 MajorAdd OpenTelemetry tracing decorator to this async endpoint.
read_documentis async and currently not wrapped with the required tracing decorator.As per coding guidelines, "Use
@trace_async(span_name, tracer_name, extract_attributes)decorator to trace entire async functions in OpenTelemetry".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/app/api/endpoints/internal/rag.py` around lines 721 - 726, Add the OpenTelemetry async tracing decorator to the read_document endpoint: apply `@trace_async` with a descriptive span name (e.g., "read_document"), the appropriate tracer_name (e.g., "backend.rag" or project tracer), and the extract_attributes callable you use elsewhere so the entire async function is traced; ensure trace_async is imported at the top of the module and place the decorator immediately above the async def read_document(...) declaration.backend/app/services/rag/document_read_service.py (1)
139-149: 🛠️ Refactor suggestion | 🟠 MajorAdd OpenTelemetry tracing decorator to this sync service method.
read_documentsis a core sync path and should be wrapped with the required sync tracing decorator.As per coding guidelines, "Use
@trace_sync(span_name, tracer_name, extract_attributes)decorator to trace entire sync functions in OpenTelemetry".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/app/services/rag/document_read_service.py` around lines 139 - 149, Add the OpenTelemetry sync tracing decorator to the read_documents method: import trace_sync and apply `@trace_sync`("document_read_service.read_documents", "backend.rag", extract_attributes) immediately above def read_documents(...). If an extract_attributes helper already exists (or a project-standard extractor like extract_attributes_from_kwargs), pass that; otherwise implement a small extractor that pulls key fields (document_ids, knowledge_base_ids, user_id, user_subtask_id, offset, limit) from the function kwargs. Ensure you import trace_sync (and the extractor if needed) so the decorator is available and the method is traced end-to-end.
🧹 Nitpick comments (2)
backend/tests/mcp_server/test_tools.py (1)
27-32: Consider extracting a shared module-loader helper.
get_silent_exit_module()andget_knowledge_module()duplicate the same import/cache pattern; a parameterized helper would reduce maintenance overhead.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/tests/mcp_server/test_tools.py` around lines 27 - 32, Extract the duplicate import/caching logic from get_silent_exit_module() and get_knowledge_module() into a single parameterized helper (e.g., load_cached_module(module_name) or _get_module(name)) that takes the module name string, checks sys.modules, calls importlib.import_module when missing, and returns sys.modules[module_name]; then update both get_silent_exit_module() and get_knowledge_module() to call this helper (preserving their docstrings/semantics) so the import/cache pattern isn’t duplicated.backend/app/api/endpoints/internal/rag.py (1)
755-761: Add a fallback for non-mapped error entries.If a future result contains
errorbut an unknown/missingerror_code, this path can currently return 200 with partial defaults. Consider a generic fallback likeif result.get("error"): raise HTTPException(400, detail=result["error"]).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/app/api/endpoints/internal/rag.py` around lines 755 - 761, The current branch that checks result and error codes (using DOCUMENT_READ_ERROR_NOT_FOUND and DOCUMENT_READ_ERROR_ACCESS_DENIED and raising HTTPException) should also handle generic error entries: after the existing checks for not found and access denied, add a fallback that if result.get("error") is present and result.get("error_code") is not recognized, raise HTTPException(status_code=400, detail=result["error"]) so unknown/mapped error messages don't accidentally return 200; ensure this check occurs before any successful 200 response is returned.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@backend/tests/mcp_server/test_tools.py`:
- Around line 27-32: Add missing return type annotations: annotate
get_knowledge_module with -> ModuleType and ensure you import ModuleType (from
types import ModuleType) at the top; for other new functions in this file (lines
referenced in review) add explicit return annotations (-> None for functions
that don't return anything, or the correct ModuleType/other types for those that
do). Update any imports to include typing symbols and run the linters/formatters
to satisfy PEP8 and the repo typing rule.
---
Outside diff comments:
In `@backend/app/api/endpoints/internal/rag.py`:
- Around line 721-726: Add the OpenTelemetry async tracing decorator to the
read_document endpoint: apply `@trace_async` with a descriptive span name (e.g.,
"read_document"), the appropriate tracer_name (e.g., "backend.rag" or project
tracer), and the extract_attributes callable you use elsewhere so the entire
async function is traced; ensure trace_async is imported at the top of the
module and place the decorator immediately above the async def
read_document(...) declaration.
In `@backend/app/services/rag/document_read_service.py`:
- Around line 139-149: Add the OpenTelemetry sync tracing decorator to the
read_documents method: import trace_sync and apply
`@trace_sync`("document_read_service.read_documents", "backend.rag",
extract_attributes) immediately above def read_documents(...). If an
extract_attributes helper already exists (or a project-standard extractor like
extract_attributes_from_kwargs), pass that; otherwise implement a small
extractor that pulls key fields (document_ids, knowledge_base_ids, user_id,
user_subtask_id, offset, limit) from the function kwargs. Ensure you import
trace_sync (and the extractor if needed) so the decorator is available and the
method is traced end-to-end.
---
Nitpick comments:
In `@backend/app/api/endpoints/internal/rag.py`:
- Around line 755-761: The current branch that checks result and error codes
(using DOCUMENT_READ_ERROR_NOT_FOUND and DOCUMENT_READ_ERROR_ACCESS_DENIED and
raising HTTPException) should also handle generic error entries: after the
existing checks for not found and access denied, add a fallback that if
result.get("error") is present and result.get("error_code") is not recognized,
raise HTTPException(status_code=400, detail=result["error"]) so unknown/mapped
error messages don't accidentally return 200; ensure this check occurs before
any successful 200 response is returned.
In `@backend/tests/mcp_server/test_tools.py`:
- Around line 27-32: Extract the duplicate import/caching logic from
get_silent_exit_module() and get_knowledge_module() into a single parameterized
helper (e.g., load_cached_module(module_name) or _get_module(name)) that takes
the module name string, checks sys.modules, calls importlib.import_module when
missing, and returns sys.modules[module_name]; then update both
get_silent_exit_module() and get_knowledge_module() to call this helper
(preserving their docstrings/semantics) so the import/cache pattern isn’t
duplicated.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: d0fc85db-21c9-4d70-82e5-748e9a5f50ce
📒 Files selected for processing (11)
backend/app/api/endpoints/internal/rag.pybackend/app/api/endpoints/knowledge.pybackend/app/schemas/knowledge.pybackend/app/services/knowledge/orchestrator.pybackend/app/services/rag/document_read_service.pybackend/init_data/skills/wegent-knowledge/SKILL.mdbackend/tests/api/endpoints/test_knowledge_document_detail_endpoints.pybackend/tests/mcp_server/test_tools.pybackend/tests/services/knowledge/test_orchestrator.pybackend/tests/services/rag/test_document_read_service.pydocs/specs/knowledge/2026-03-30-wegent-knowledge-document-read-design.md
✅ Files skipped from review due to trivial changes (3)
- backend/app/schemas/knowledge.py
- docs/specs/knowledge/2026-03-30-wegent-knowledge-document-read-design.md
- backend/tests/api/endpoints/test_knowledge_document_detail_endpoints.py
🚧 Files skipped from review as they are similar to previous changes (4)
- backend/init_data/skills/wegent-knowledge/SKILL.md
- backend/tests/services/knowledge/test_orchestrator.py
- backend/app/services/knowledge/orchestrator.py
- backend/app/api/endpoints/knowledge.py
| def get_knowledge_module(): | ||
| """Get the knowledge module, handling import caching issues.""" | ||
| module_name = "app.mcp_server.tools.knowledge" | ||
| if module_name not in sys.modules: | ||
| importlib.import_module(module_name) | ||
| return sys.modules[module_name] |
There was a problem hiding this comment.
Add return type hints to new Python functions.
Newly added functions/methods are missing return annotations (-> ModuleType / -> None), which breaks the repo’s Python typing rule.
Proposed diff
import importlib
import inspect
import json
import sys
+from types import ModuleType
from unittest.mock import MagicMock, patch
@@
-def get_knowledge_module():
+def get_knowledge_module() -> ModuleType:
@@
- def test_read_document_content_returns_orchestrator_payload(self):
+ def test_read_document_content_returns_orchestrator_payload(self) -> None:
@@
- def test_read_document_content_returns_error_dict_for_validation_failure(self):
+ def test_read_document_content_returns_error_dict_for_validation_failure(
+ self,
+ ) -> None:
@@
- def test_read_document_content_returns_error_dict_for_unexpected_failure(self):
+ def test_read_document_content_returns_error_dict_for_unexpected_failure(
+ self,
+ ) -> None:
@@
- def test_read_document_content_uses_shared_default_limit_constant(self):
+ def test_read_document_content_uses_shared_default_limit_constant(
+ self,
+ ) -> None:As per coding guidelines, **/*.py: Python: Follow PEP 8, Black formatter (line length: 88), isort, type hints required.
Also applies to: 122-251
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@backend/tests/mcp_server/test_tools.py` around lines 27 - 32, Add missing
return type annotations: annotate get_knowledge_module with -> ModuleType and
ensure you import ModuleType (from types import ModuleType) at the top; for
other new functions in this file (lines referenced in review) add explicit
return annotations (-> None for functions that don't return anything, or the
correct ModuleType/other types for those that do). Update any imports to include
typing symbols and run the linters/formatters to satisfy PEP8 and the repo
typing rule.
* docs(backend): add knowledge document read spec and plan * feat(backend): add orchestrated knowledge document reads * fix(backend): tighten knowledge document read handling
* docs(backend): add knowledge document read spec and plan * feat(backend): add orchestrated knowledge document reads * fix(backend): tighten knowledge document read handling
* feat: add workspace archive and recovery for Pod deletion Implement Pod recovery feature that allows users to continue conversations after executor Pods are deleted: - Add ArchiveInfo schema to store archive metadata in Task.status.archive - Add workspace_archive service for MinIO presigned URL generation - Add archive/restore endpoints in executor and executor_manager - Add ExecutorRecoveryService for Pod recreation with workspace restoration - Add skip_git_clone support to prevent git clone conflicts during restore - Add Celery Beat scheduled task for expired archive cleanup (30-day retention) - Integrate archive workflow in executor_job before Pod deletion Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(backend): add missing minio dependency Add minio package to backend dependencies for workspace archive storage. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat(admin): add created_at field to device monitor list (#846) - Add created_at field to AdminDeviceInfo schema in backend - Add created_at to AdminDeviceInfo TypeScript interface - Display creation time in device list UI - Add i18n translations for created_at column (zh-CN and en) Co-authored-by: yunpeng7 <yunpeng7@staff.weibo.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * perf: use async heartbeat (#849) * fix(chat_shell): prevent orphaned tool call IDs in group chat history (#852) * fix(chat_shell): prevent tool call group splitting in group chat history truncation _truncate_history blindly sliced the flat message list, which could split assistant+tool_calls and their tool response messages across the truncation boundary. This produced orphaned function_call_output items without matching function_call entries in the OpenAI Responses API format, causing 'No tool call found for function call output' errors. Add _group_messages() to treat assistant+tool_calls+tool responses as atomic units, and modify _truncate_history() to truncate by groups instead of individual messages. * fix(chat_shell): ensure tool call group integrity across all compression paths Extract group_tool_call_messages() into shared messages/utils.py and apply atomic group handling to: - HistoryTruncationStrategy.compress(): adjust first/last boundaries to avoid splitting tool call groups, add post-removal orphan cleanup - _force_compression_to_target(): Step 2 removes middle groups instead of individual messages, Step 5 keeps first/last groups - Refactor loader.py to import shared utility instead of inline helper All 95 related tests pass. Comprehensive audit confirms no other code paths in chat_shell break tool call group integrity. * test(chat_shell): add tool-call group truncation regressions Add regression coverage for preserving assistant tool calls with their matching tool results across group-chat history truncation, history compression boundaries, and forced compression fallback paths. * fix: 在里面智能体的创建人和机器人的创建人不是一个人时会报错 (#853) * docs: update contributors list * docs: update contributors list (zh) * docs: update contributors list * docs: update contributors list (zh) * fix: 在里面智能体的创建人和机器人的创建人不是一个人时会报错 * fix: 迁移其他的sql到kindReader --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: hongyu9 <hongyu9@staff.weibo.com> * fix: fail fast on invalid tool call IDs across chat protocols (#854) * fix: 订阅任务执行间隔调整 & trace http接口的匹配规则调整 (#855) * docs: update contributors list * docs: update contributors list (zh) * docs: update contributors list * docs: update contributors list (zh) * fix: telemetry的匹配规则调整 * fix: 订阅任务执行间隔调整 * fix: 调整逻辑 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: hongyu9 <hongyu9@staff.weibo.com> * fix: sanitize PyInstaller LD_LIBRARY_PATH for child processes (#859) PyInstaller's bootloader prepends its extraction directory (/tmp/_MEIxxxxxx) to LD_LIBRARY_PATH, causing child processes (Claude Code, shell commands) to load wrong shared libraries (e.g., libtinfo.so.6). Extract `sanitize_ld_library_path()` into platform_compat and apply it in both local_mode_strategy (Claude SDK subprocess) and extension_handler (extension script subprocess) to restore the original library path. See: https://pyinstaller.org/en/stable/common-issues-and-pitfalls.html Co-authored-by: sifang <sifang@staff.weibo.com> * refactor(rag): move internal retrieve routing into backend (#847) * refactor(rag): move internal retrieve routing into backend * refactor(rag): move retrieve persistence into backend * refactor(rag): move kb head persistence into backend * fix(rag): tighten backend retrieve routing * refactor(rag): simplify token estimation fallback * refactor(rag): batch route token estimation * fix(rag): token estimator decimal * fix(rag): harden kb read persistence * frontend: show 'indexing' status for documents pending indexing (#858) * fix(frontend): show 'indexing' status for documents pending indexing When a document is uploaded, is_active is false while indexing is in progress. Previously, this showed 'index unavailable' which was misleading. Now documents with status='enabled' but is_active=false will show 'indexing' instead of 'index unavailable', matching the existing translation key. Changes: - Updated compact mode status indicator (line 247) - Updated normal mode status badge (line 461) Fixes: knowledge base document shows 'index unavailable' during indexing * fix(i18n): update Developer role description in Chinese locale * fix: 修复订阅器中脏数据导致的无法展示的问题 (#860) * docs: update contributors list * docs: update contributors list (zh) * docs: update contributors list * docs: update contributors list (zh) * fix: 修复订阅器中脏数据导致的无法展示的问题 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: hongyu9 <hongyu9@staff.weibo.com> * feat(backend): add knowledge base RAG support to /v1/responses API (#844) * feat(backend): add knowledge base RAG support to /v1/responses API Implement knowledge base Q&A functionality for the OpenAI-compatible /v1/responses endpoint with the following changes: Schema Changes: - Add knowledge_base_names field to WegentTool schema - Support namespace#name format for KB specification New Services: - KnowledgeBaseNameResolver: resolves KB display names to IDs with permission checking via TaskKnowledgeBaseService - KnowledgeBaseContextCreator: creates SubtaskContext records for API-specified KBs to integrate with existing RAG pipeline Integration: - Extend parse_wegent_tools() to handle knowledge_base tool type - Add parse_knowledge_base_name() for namespace#name parsing - Modify build_execution_request() to accept knowledge_base_names - Add _create_kb_contexts_from_api_request() for KB context injection - Update openapi_responses.py endpoints to pass KB names parameter Testing: - Add comprehensive unit tests for KB name resolution - Add tests for KB context creation - Add tests for helper functions with KB support - All 32 new tests passing The implementation reuses the existing RAG flow through prepare_contexts_for_chat() and KnowledgeBaseTool, ensuring consistency with the web UI behavior. * refactor(kb_resolver): optimize database query complexity from O(n) to O(m) - Add batch_get_knowledge_base_by_names() to TaskKnowledgeBaseService for efficient batch queries - Extract _check_kb_access_permission() for unified permission checking logic - Update kb_resolver to use service methods instead of direct queries - Reduce DB queries from O(n) to O(m) where m is unique namespace count - Update tests to mock service methods instead of internal functions All 15 tests pass. * refactor(backend): optimize KB permission check in kb_resolver Simplify permission checking by using get_all_knowledge_bases_grouped() which already returns all KBs accessible to the user. Changes: - Replace _batch_query_kbs() and _check_kb_access_permission() with _get_accessible_kb_lookup() that builds a lookup dict from grouped results - Remove unused resolve_single() method and batch_get_knowledge_base_by_names() - Update tests to mock KnowledgeService.get_all_knowledge_bases_grouped() This reduces database queries and simplifies the permission check logic. * feat(backend): integrate knowledge base context creation into unified AI trigger - Add knowledge_base_names parameter to build_execution_request for OpenAPI v1/responses - Create _create_kb_contexts_from_api_request helper to process KB names from API requests - Integrate KB context processing into unified trigger flow - Add KnowledgeBaseContextCreator class for creating SubtaskContext records - Add comprehensive unit tests for KnowledgeBaseContextCreator This enables RAG functionality for OpenAPI v1/responses endpoint by creating SubtaskContext records that are processed by the existing context pipeline. * fix(chat): propagate HTTPException from KnowledgeBaseNameResolver in unified trigger - Add HTTPException import from fastapi - Catch and re-raise HTTPException explicitly in _create_kb_contexts_from_api_request - Keep generic exception handling for non-HTTP exceptions to preserve best-effort behavior - This ensures 403/404 errors from KB resolution are properly propagated to callers instead of being swallowed and logged as warnings * fix(chat_shell): use model_type for provider detection instead of model_id (#861) - Extract shared detect_provider() into models/providers.py with PROVIDER_ALIASES as single source of truth - model_type (env.model) is authoritative; raise ValueError on unknown - Remove _PROVIDER_ID_PATTERNS model_id prefix fallback (same model_id can serve multiple protocols) - Unify truncation notice logic for all providers (no system-role notice in middle of messages, preventing Anthropic non-consecutive system message errors) - Pass model_type from model_config through MessageCompressor to TokenCounter for accurate provider detection - Remove duplicate provider constants from factory.py and token_counter.py Co-authored-by: wenbo17 <wenbo17@staff.weibo.com> * ix: claude的子代理模式不可用修复 (#862) * docs: update contributors list * docs: update contributors list (zh) * docs: update contributors list * docs: update contributors list (zh) * fix: claude的子代理模式不可用修复 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: hongyu9 <hongyu9@staff.weibo.com> * feat(inbox): implement work queue and message forwarding system (#851) * feat(inbox): implement work queue and message forwarding system Add a comprehensive message forwarding and work queue system that enables users to forward conversation messages to other users. Recipients can manage received messages through work queues and optionally configure AI agents for automatic processing. Backend changes: - Add QueueMessage and RecentContact database models - Add WorkQueue CRD schema stored in kinds table - Implement work queue services for CRUD operations - Implement message forwarding service with queue selection - Add WebSocket events for real-time notifications - Add API endpoints for work queue management - Add ForbiddenException to core exceptions Frontend changes: - Add inbox page with queue sidebar and message list - Implement ForwardMessageDialog for recipient selection - Add queue edit/create dialog with auto-processing config - Add message detail dialog with content preview - Add i18n translations (zh-CN and en) - Register inbox route and navigation * fix: resolve lint errors in inbox feature - Remove unused imports (RefreshCw, Settings, Menu, Button, Input, Clock) - Format Python files with Black * fix: resolve TypeScript errors in inbox feature - Add 'flow' and 'inbox' to TopNavigation activePage type - Replace Badge variant 'outline' with 'info' (outline not supported) * fix: address CodeRabbit review comments for work queue feature - Fix status parameter shadowing fastapi status module in work_queue.py - Fix NamespaceMember.namespace to use group_name column reference - Replace func.json_set with Python-level update for PostgreSQL compatibility - Fix refreshQueues dependency loop using functional state update - Remove Chinese text from inbox page comment - Add NaN validation for schedule interval input - Replace clickable Badge with accessible button for recent contacts --------- Co-authored-by: qdaxb <4157870+qdaxb@users.noreply.github.com> * Wegent/work queue and message forwarding (#863) * feat(inbox): implement work queue and message forwarding system Add a comprehensive message forwarding and work queue system that enables users to forward conversation messages to other users. Recipients can manage received messages through work queues and optionally configure AI agents for automatic processing. Backend changes: - Add QueueMessage and RecentContact database models - Add WorkQueue CRD schema stored in kinds table - Implement work queue services for CRUD operations - Implement message forwarding service with queue selection - Add WebSocket events for real-time notifications - Add API endpoints for work queue management - Add ForbiddenException to core exceptions Frontend changes: - Add inbox page with queue sidebar and message list - Implement ForwardMessageDialog for recipient selection - Add queue edit/create dialog with auto-processing config - Add message detail dialog with content preview - Add i18n translations (zh-CN and en) - Register inbox route and navigation * fix: resolve lint errors in inbox feature - Remove unused imports (RefreshCw, Settings, Menu, Button, Input, Clock) - Format Python files with Black * fix: resolve TypeScript errors in inbox feature - Add 'flow' and 'inbox' to TopNavigation activePage type - Replace Badge variant 'outline' with 'info' (outline not supported) * fix: address CodeRabbit review comments for work queue feature - Fix status parameter shadowing fastapi status module in work_queue.py - Fix NamespaceMember.namespace to use group_name column reference - Replace func.json_set with Python-level update for PostgreSQL compatibility - Fix refreshQueues dependency loop using functional state update - Remove Chinese text from inbox page comment - Add NaN validation for schedule interval input - Replace clickable Badge with accessible button for recent contacts * feat: update work queue --------- Co-authored-by: qdaxb <4157870+qdaxb@users.noreply.github.com> * fix: fix column default value * fix: fix forward message click * feat: remove unused area * feat: add inbox default message * fix: 修复脏数据导致的订阅任务无法执行的问题 (#865) * docs: update contributors list * docs: update contributors list (zh) * docs: update contributors list * docs: update contributors list (zh) * fix: 修复脏数据导致的订阅任务无法执行的问题 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: hongyu9 <hongyu9@staff.weibo.com> * fix(browser): harden browser-tool linux recovery (#867) Co-authored-by: sifang <sifang@staff.weibo.com> * fix: 修复无法使用自定义镜像以及自定义镜像无法校验的问题 (#866) * docs: update contributors list * docs: update contributors list (zh) * docs: update contributors list * docs: update contributors list (zh) * fix: 修复无法使用自定义镜像 * fix: 修复无法使用自定义镜像以及自定义镜像无法校验的问题 * fix: 修复可能的bug --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: hongyu9 <hongyu9@staff.weibo.com> * fix: fix welcome timezone (#868) * docs: update inbox docs (#869) * fix: 修复单测 (#870) * docs: update contributors list * docs: update contributors list (zh) * docs: update contributors list * docs: update contributors list (zh) * fix: 修复单测 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: hongyu9 <hongyu9@staff.weibo.com> * fix: fix page error (#871) * fix: data-roleid="api-key-create-button" not in html attr (#873) * fix: 修复停止按钮偶发变成发送的问题 & 修复失败的消息会丢失的问题 (#876) * docs: update contributors list * docs: update contributors list (zh) * docs: update contributors list * docs: update contributors list (zh) * fix: 修复停止按钮偶发变成发送的问题 * fix: 修复失败的消息会丢失的问题 * fix: 修复类型报错 * fix: 修复前端复制按钮内容错误的问题 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: hongyu9 <hongyu9@staff.weibo.com> * fix: 修复“skill not found” (#877) * docs: update contributors list * docs: update contributors list (zh) * docs: update contributors list * docs: update contributors list (zh) * fix: 技能错乱 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: hongyu9 <hongyu9@staff.weibo.com> * chore(executor): upgrade claude-agent-sdk from 0.1.31 to 0.1.51 (#880) Co-authored-by: sifang <sifang@staff.weibo.com> * feat(frontend): add HTML attachment preview and share link generation (#872) - Add HtmlPreview component for previewing HTML files with iframe and source view modes - Update FilePreview to support HTML file type detection and rendering - Add createAttachmentShareLink API for generating public share links - Add share button to FilePreviewDialog and FilePreviewPage (visible for owners only) - Add Web Page type label and icon for HTML attachments in AttachmentCard - Fix preview page height to fill viewport using h-screen and h-full - Update AttachmentPreview to support HTML file preview button Fixes share link browsing and download for table-type attachments * fix(knowledge): harden document indexing state (#875) * fix(knowledge): harden document indexing state * fix(knowledge): harden indexing state transitions * fix(knowledge): tighten reindex review followups * fix(rag): KNOWLEDGE_INDEX_LOCK_MAX_RETRIES=1 * fix(knowledge): store index status without db enum * fix(alembic): correct migration revision metadata * docs: update contributors list (zh) (#879) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * docs: update contributors list (#878) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * feat: 支持skill认证 (#882) * docs: update contributors list * docs: update contributors list (zh) * docs: update contributors list * docs: update contributors list (zh) * docs: add skill http identity design and plan * feat(skill): add http identity token flow * feat: 修改样式 * feat: 修改样式 * feat: 移除计划 * feat: 调整为带有认证的接口 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: hongyu9 <hongyu9@staff.weibo.com> # Conflicts: # executor_manager/services/sandbox/manager.py * Feature/knowledge document read (#888) * docs(backend): add knowledge document read spec and plan * feat(backend): add orchestrated knowledge document reads * fix(backend): tighten knowledge document read handling * refactor(web-scraper): add configuration for specific sites that require special handling (#884) * refactor(web-scraper): extract site-specific config to scraper_config.py - Add scraper_config.py for site-specific crawling configurations * fix(web_scraper): load WEB_SCRAPER_SITE_CONFIG from Pydantic settings instead of os.environ - Add WEB_SCRAPER_SITE_CONFIG to Settings class in config.py - Refactor scraper_config.py to use settings.WEB_SCRAPER_SITE_CONFIG with proper logging - Replace module-level config loading with cached get_site_config() function - Update scraper_service.py to use new get_site_config() function - Add detailed logging for site config matching and application - Fix remove_overlay_elements duplicate key in CrawlerRunConfig This ensures the configuration is properly loaded from .env file via Pydantic settings." * refactor(backend): improve scraper_config security and type safety - Remove sensitive config value from INFO level logging - Add return type annotations to _load_site_config and get_site_config - Replace broad Exception catch with specific exception types (AttributeError, KeyError, TypeError, ValueError) - Import Dict and Any from typing module * refactor(backend): replace auto-cleanup with archive expiration check Remove automatic MinIO archive cleanup (Celery Beat task) and instead block task execution when workspace archive has expired (>30 days). Users will receive a clear error message and must create a new task. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: 添加恢复行为测试和脚本路径修正 * fix: 使用 timezone.utc 替换 UTC 以确保时区正确 * test(backend): fix workspace recovery test patches --------- Co-authored-by: yunpeng7 <yunpeng7@staff.weibo.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: axb <qindi@staff.weibo.com> Co-authored-by: moqimoqidea <39821951+moqimoqidea@users.noreply.github.com> Co-authored-by: MicroLee <yudexiaozhou@gmail.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: hongyu9 <hongyu9@staff.weibo.com> Co-authored-by: icycrystal4 <icycrystal4@gmail.com> Co-authored-by: sifang <sifang@staff.weibo.com> Co-authored-by: Yanhe <yanhe1@staff.weibo.com> Co-authored-by: parabala <chenyong1@staff.weibo.com> Co-authored-by: wenbo17 <wenbo17@staff.weibo.com> Co-authored-by: qdaxb <4157870+qdaxb@users.noreply.github.com> Co-authored-by: 李枨煊 <chengxuan@staff.weibo.com> Co-authored-by: johnny0120 <jiangyang7@staff.weibo.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* feat: add workspace archive and recovery for Pod deletion Implement Pod recovery feature that allows users to continue conversations after executor Pods are deleted: - Add ArchiveInfo schema to store archive metadata in Task.status.archive - Add workspace_archive service for MinIO presigned URL generation - Add archive/restore endpoints in executor and executor_manager - Add ExecutorRecoveryService for Pod recreation with workspace restoration - Add skip_git_clone support to prevent git clone conflicts during restore - Add Celery Beat scheduled task for expired archive cleanup (30-day retention) - Integrate archive workflow in executor_job before Pod deletion Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(backend): add missing minio dependency Add minio package to backend dependencies for workspace archive storage. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat(admin): add created_at field to device monitor list (#846) - Add created_at field to AdminDeviceInfo schema in backend - Add created_at to AdminDeviceInfo TypeScript interface - Display creation time in device list UI - Add i18n translations for created_at column (zh-CN and en) Co-authored-by: yunpeng7 <yunpeng7@staff.weibo.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * perf: use async heartbeat (#849) * fix(chat_shell): prevent orphaned tool call IDs in group chat history (#852) * fix(chat_shell): prevent tool call group splitting in group chat history truncation _truncate_history blindly sliced the flat message list, which could split assistant+tool_calls and their tool response messages across the truncation boundary. This produced orphaned function_call_output items without matching function_call entries in the OpenAI Responses API format, causing 'No tool call found for function call output' errors. Add _group_messages() to treat assistant+tool_calls+tool responses as atomic units, and modify _truncate_history() to truncate by groups instead of individual messages. * fix(chat_shell): ensure tool call group integrity across all compression paths Extract group_tool_call_messages() into shared messages/utils.py and apply atomic group handling to: - HistoryTruncationStrategy.compress(): adjust first/last boundaries to avoid splitting tool call groups, add post-removal orphan cleanup - _force_compression_to_target(): Step 2 removes middle groups instead of individual messages, Step 5 keeps first/last groups - Refactor loader.py to import shared utility instead of inline helper All 95 related tests pass. Comprehensive audit confirms no other code paths in chat_shell break tool call group integrity. * test(chat_shell): add tool-call group truncation regressions Add regression coverage for preserving assistant tool calls with their matching tool results across group-chat history truncation, history compression boundaries, and forced compression fallback paths. * fix: 在里面智能体的创建人和机器人的创建人不是一个人时会报错 (#853) * docs: update contributors list * docs: update contributors list (zh) * docs: update contributors list * docs: update contributors list (zh) * fix: 在里面智能体的创建人和机器人的创建人不是一个人时会报错 * fix: 迁移其他的sql到kindReader --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: hongyu9 <hongyu9@staff.weibo.com> * fix: fail fast on invalid tool call IDs across chat protocols (#854) * fix: 订阅任务执行间隔调整 & trace http接口的匹配规则调整 (#855) * docs: update contributors list * docs: update contributors list (zh) * docs: update contributors list * docs: update contributors list (zh) * fix: telemetry的匹配规则调整 * fix: 订阅任务执行间隔调整 * fix: 调整逻辑 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: hongyu9 <hongyu9@staff.weibo.com> * fix: sanitize PyInstaller LD_LIBRARY_PATH for child processes (#859) PyInstaller's bootloader prepends its extraction directory (/tmp/_MEIxxxxxx) to LD_LIBRARY_PATH, causing child processes (Claude Code, shell commands) to load wrong shared libraries (e.g., libtinfo.so.6). Extract `sanitize_ld_library_path()` into platform_compat and apply it in both local_mode_strategy (Claude SDK subprocess) and extension_handler (extension script subprocess) to restore the original library path. See: https://pyinstaller.org/en/stable/common-issues-and-pitfalls.html Co-authored-by: sifang <sifang@staff.weibo.com> * refactor(rag): move internal retrieve routing into backend (#847) * refactor(rag): move internal retrieve routing into backend * refactor(rag): move retrieve persistence into backend * refactor(rag): move kb head persistence into backend * fix(rag): tighten backend retrieve routing * refactor(rag): simplify token estimation fallback * refactor(rag): batch route token estimation * fix(rag): token estimator decimal * fix(rag): harden kb read persistence * frontend: show 'indexing' status for documents pending indexing (#858) * fix(frontend): show 'indexing' status for documents pending indexing When a document is uploaded, is_active is false while indexing is in progress. Previously, this showed 'index unavailable' which was misleading. Now documents with status='enabled' but is_active=false will show 'indexing' instead of 'index unavailable', matching the existing translation key. Changes: - Updated compact mode status indicator (line 247) - Updated normal mode status badge (line 461) Fixes: knowledge base document shows 'index unavailable' during indexing * fix(i18n): update Developer role description in Chinese locale * fix: 修复订阅器中脏数据导致的无法展示的问题 (#860) * docs: update contributors list * docs: update contributors list (zh) * docs: update contributors list * docs: update contributors list (zh) * fix: 修复订阅器中脏数据导致的无法展示的问题 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: hongyu9 <hongyu9@staff.weibo.com> * feat(backend): add knowledge base RAG support to /v1/responses API (#844) * feat(backend): add knowledge base RAG support to /v1/responses API Implement knowledge base Q&A functionality for the OpenAI-compatible /v1/responses endpoint with the following changes: Schema Changes: - Add knowledge_base_names field to WegentTool schema - Support namespace#name format for KB specification New Services: - KnowledgeBaseNameResolver: resolves KB display names to IDs with permission checking via TaskKnowledgeBaseService - KnowledgeBaseContextCreator: creates SubtaskContext records for API-specified KBs to integrate with existing RAG pipeline Integration: - Extend parse_wegent_tools() to handle knowledge_base tool type - Add parse_knowledge_base_name() for namespace#name parsing - Modify build_execution_request() to accept knowledge_base_names - Add _create_kb_contexts_from_api_request() for KB context injection - Update openapi_responses.py endpoints to pass KB names parameter Testing: - Add comprehensive unit tests for KB name resolution - Add tests for KB context creation - Add tests for helper functions with KB support - All 32 new tests passing The implementation reuses the existing RAG flow through prepare_contexts_for_chat() and KnowledgeBaseTool, ensuring consistency with the web UI behavior. * refactor(kb_resolver): optimize database query complexity from O(n) to O(m) - Add batch_get_knowledge_base_by_names() to TaskKnowledgeBaseService for efficient batch queries - Extract _check_kb_access_permission() for unified permission checking logic - Update kb_resolver to use service methods instead of direct queries - Reduce DB queries from O(n) to O(m) where m is unique namespace count - Update tests to mock service methods instead of internal functions All 15 tests pass. * refactor(backend): optimize KB permission check in kb_resolver Simplify permission checking by using get_all_knowledge_bases_grouped() which already returns all KBs accessible to the user. Changes: - Replace _batch_query_kbs() and _check_kb_access_permission() with _get_accessible_kb_lookup() that builds a lookup dict from grouped results - Remove unused resolve_single() method and batch_get_knowledge_base_by_names() - Update tests to mock KnowledgeService.get_all_knowledge_bases_grouped() This reduces database queries and simplifies the permission check logic. * feat(backend): integrate knowledge base context creation into unified AI trigger - Add knowledge_base_names parameter to build_execution_request for OpenAPI v1/responses - Create _create_kb_contexts_from_api_request helper to process KB names from API requests - Integrate KB context processing into unified trigger flow - Add KnowledgeBaseContextCreator class for creating SubtaskContext records - Add comprehensive unit tests for KnowledgeBaseContextCreator This enables RAG functionality for OpenAPI v1/responses endpoint by creating SubtaskContext records that are processed by the existing context pipeline. * fix(chat): propagate HTTPException from KnowledgeBaseNameResolver in unified trigger - Add HTTPException import from fastapi - Catch and re-raise HTTPException explicitly in _create_kb_contexts_from_api_request - Keep generic exception handling for non-HTTP exceptions to preserve best-effort behavior - This ensures 403/404 errors from KB resolution are properly propagated to callers instead of being swallowed and logged as warnings * fix(chat_shell): use model_type for provider detection instead of model_id (#861) - Extract shared detect_provider() into models/providers.py with PROVIDER_ALIASES as single source of truth - model_type (env.model) is authoritative; raise ValueError on unknown - Remove _PROVIDER_ID_PATTERNS model_id prefix fallback (same model_id can serve multiple protocols) - Unify truncation notice logic for all providers (no system-role notice in middle of messages, preventing Anthropic non-consecutive system message errors) - Pass model_type from model_config through MessageCompressor to TokenCounter for accurate provider detection - Remove duplicate provider constants from factory.py and token_counter.py Co-authored-by: wenbo17 <wenbo17@staff.weibo.com> * ix: claude的子代理模式不可用修复 (#862) * docs: update contributors list * docs: update contributors list (zh) * docs: update contributors list * docs: update contributors list (zh) * fix: claude的子代理模式不可用修复 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: hongyu9 <hongyu9@staff.weibo.com> * feat(inbox): implement work queue and message forwarding system (#851) * feat(inbox): implement work queue and message forwarding system Add a comprehensive message forwarding and work queue system that enables users to forward conversation messages to other users. Recipients can manage received messages through work queues and optionally configure AI agents for automatic processing. Backend changes: - Add QueueMessage and RecentContact database models - Add WorkQueue CRD schema stored in kinds table - Implement work queue services for CRUD operations - Implement message forwarding service with queue selection - Add WebSocket events for real-time notifications - Add API endpoints for work queue management - Add ForbiddenException to core exceptions Frontend changes: - Add inbox page with queue sidebar and message list - Implement ForwardMessageDialog for recipient selection - Add queue edit/create dialog with auto-processing config - Add message detail dialog with content preview - Add i18n translations (zh-CN and en) - Register inbox route and navigation * fix: resolve lint errors in inbox feature - Remove unused imports (RefreshCw, Settings, Menu, Button, Input, Clock) - Format Python files with Black * fix: resolve TypeScript errors in inbox feature - Add 'flow' and 'inbox' to TopNavigation activePage type - Replace Badge variant 'outline' with 'info' (outline not supported) * fix: address CodeRabbit review comments for work queue feature - Fix status parameter shadowing fastapi status module in work_queue.py - Fix NamespaceMember.namespace to use group_name column reference - Replace func.json_set with Python-level update for PostgreSQL compatibility - Fix refreshQueues dependency loop using functional state update - Remove Chinese text from inbox page comment - Add NaN validation for schedule interval input - Replace clickable Badge with accessible button for recent contacts --------- Co-authored-by: qdaxb <4157870+qdaxb@users.noreply.github.com> * Wegent/work queue and message forwarding (#863) * feat(inbox): implement work queue and message forwarding system Add a comprehensive message forwarding and work queue system that enables users to forward conversation messages to other users. Recipients can manage received messages through work queues and optionally configure AI agents for automatic processing. Backend changes: - Add QueueMessage and RecentContact database models - Add WorkQueue CRD schema stored in kinds table - Implement work queue services for CRUD operations - Implement message forwarding service with queue selection - Add WebSocket events for real-time notifications - Add API endpoints for work queue management - Add ForbiddenException to core exceptions Frontend changes: - Add inbox page with queue sidebar and message list - Implement ForwardMessageDialog for recipient selection - Add queue edit/create dialog with auto-processing config - Add message detail dialog with content preview - Add i18n translations (zh-CN and en) - Register inbox route and navigation * fix: resolve lint errors in inbox feature - Remove unused imports (RefreshCw, Settings, Menu, Button, Input, Clock) - Format Python files with Black * fix: resolve TypeScript errors in inbox feature - Add 'flow' and 'inbox' to TopNavigation activePage type - Replace Badge variant 'outline' with 'info' (outline not supported) * fix: address CodeRabbit review comments for work queue feature - Fix status parameter shadowing fastapi status module in work_queue.py - Fix NamespaceMember.namespace to use group_name column reference - Replace func.json_set with Python-level update for PostgreSQL compatibility - Fix refreshQueues dependency loop using functional state update - Remove Chinese text from inbox page comment - Add NaN validation for schedule interval input - Replace clickable Badge with accessible button for recent contacts * feat: update work queue --------- Co-authored-by: qdaxb <4157870+qdaxb@users.noreply.github.com> * fix: fix column default value * fix: fix forward message click * feat: remove unused area * feat: add inbox default message * fix: 修复脏数据导致的订阅任务无法执行的问题 (#865) * docs: update contributors list * docs: update contributors list (zh) * docs: update contributors list * docs: update contributors list (zh) * fix: 修复脏数据导致的订阅任务无法执行的问题 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: hongyu9 <hongyu9@staff.weibo.com> * fix(browser): harden browser-tool linux recovery (#867) Co-authored-by: sifang <sifang@staff.weibo.com> * fix: 修复无法使用自定义镜像以及自定义镜像无法校验的问题 (#866) * docs: update contributors list * docs: update contributors list (zh) * docs: update contributors list * docs: update contributors list (zh) * fix: 修复无法使用自定义镜像 * fix: 修复无法使用自定义镜像以及自定义镜像无法校验的问题 * fix: 修复可能的bug --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: hongyu9 <hongyu9@staff.weibo.com> * fix: fix welcome timezone (#868) * docs: update inbox docs (#869) * fix: 修复单测 (#870) * docs: update contributors list * docs: update contributors list (zh) * docs: update contributors list * docs: update contributors list (zh) * fix: 修复单测 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: hongyu9 <hongyu9@staff.weibo.com> * fix: fix page error (#871) * fix: data-roleid="api-key-create-button" not in html attr (#873) * fix: 修复停止按钮偶发变成发送的问题 & 修复失败的消息会丢失的问题 (#876) * docs: update contributors list * docs: update contributors list (zh) * docs: update contributors list * docs: update contributors list (zh) * fix: 修复停止按钮偶发变成发送的问题 * fix: 修复失败的消息会丢失的问题 * fix: 修复类型报错 * fix: 修复前端复制按钮内容错误的问题 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: hongyu9 <hongyu9@staff.weibo.com> * fix: 修复“skill not found” (#877) * docs: update contributors list * docs: update contributors list (zh) * docs: update contributors list * docs: update contributors list (zh) * fix: 技能错乱 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: hongyu9 <hongyu9@staff.weibo.com> * chore(executor): upgrade claude-agent-sdk from 0.1.31 to 0.1.51 (#880) Co-authored-by: sifang <sifang@staff.weibo.com> * feat(frontend): add HTML attachment preview and share link generation (#872) - Add HtmlPreview component for previewing HTML files with iframe and source view modes - Update FilePreview to support HTML file type detection and rendering - Add createAttachmentShareLink API for generating public share links - Add share button to FilePreviewDialog and FilePreviewPage (visible for owners only) - Add Web Page type label and icon for HTML attachments in AttachmentCard - Fix preview page height to fill viewport using h-screen and h-full - Update AttachmentPreview to support HTML file preview button Fixes share link browsing and download for table-type attachments * fix(knowledge): harden document indexing state (#875) * fix(knowledge): harden document indexing state * fix(knowledge): harden indexing state transitions * fix(knowledge): tighten reindex review followups * fix(rag): KNOWLEDGE_INDEX_LOCK_MAX_RETRIES=1 * fix(knowledge): store index status without db enum * fix(alembic): correct migration revision metadata * docs: update contributors list (zh) (#879) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * docs: update contributors list (#878) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * feat: 支持skill认证 (#882) * docs: update contributors list * docs: update contributors list (zh) * docs: update contributors list * docs: update contributors list (zh) * docs: add skill http identity design and plan * feat(skill): add http identity token flow * feat: 修改样式 * feat: 修改样式 * feat: 移除计划 * feat: 调整为带有认证的接口 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: hongyu9 <hongyu9@staff.weibo.com> # Conflicts: # executor_manager/services/sandbox/manager.py * Feature/knowledge document read (#888) * docs(backend): add knowledge document read spec and plan * feat(backend): add orchestrated knowledge document reads * fix(backend): tighten knowledge document read handling * refactor(web-scraper): add configuration for specific sites that require special handling (#884) * refactor(web-scraper): extract site-specific config to scraper_config.py - Add scraper_config.py for site-specific crawling configurations * fix(web_scraper): load WEB_SCRAPER_SITE_CONFIG from Pydantic settings instead of os.environ - Add WEB_SCRAPER_SITE_CONFIG to Settings class in config.py - Refactor scraper_config.py to use settings.WEB_SCRAPER_SITE_CONFIG with proper logging - Replace module-level config loading with cached get_site_config() function - Update scraper_service.py to use new get_site_config() function - Add detailed logging for site config matching and application - Fix remove_overlay_elements duplicate key in CrawlerRunConfig This ensures the configuration is properly loaded from .env file via Pydantic settings." * refactor(backend): improve scraper_config security and type safety - Remove sensitive config value from INFO level logging - Add return type annotations to _load_site_config and get_site_config - Replace broad Exception catch with specific exception types (AttributeError, KeyError, TypeError, ValueError) - Import Dict and Any from typing module * refactor(backend): replace auto-cleanup with archive expiration check Remove automatic MinIO archive cleanup (Celery Beat task) and instead block task execution when workspace archive has expired (>30 days). Users will receive a clear error message and must create a new task. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: 添加恢复行为测试和脚本路径修正 * fix: 使用 timezone.utc 替换 UTC 以确保时区正确 * test(backend): fix workspace recovery test patches * feat: 添加工作区归档配置测试与默认值 * feat: 添加工作区归档时区配置及测试 --------- Co-authored-by: yunpeng7 <yunpeng7@staff.weibo.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: axb <qindi@staff.weibo.com> Co-authored-by: moqimoqidea <39821951+moqimoqidea@users.noreply.github.com> Co-authored-by: MicroLee <yudexiaozhou@gmail.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: hongyu9 <hongyu9@staff.weibo.com> Co-authored-by: icycrystal4 <icycrystal4@gmail.com> Co-authored-by: sifang <sifang@staff.weibo.com> Co-authored-by: Yanhe <yanhe1@staff.weibo.com> Co-authored-by: parabala <chenyong1@staff.weibo.com> Co-authored-by: wenbo17 <wenbo17@staff.weibo.com> Co-authored-by: qdaxb <4157870+qdaxb@users.noreply.github.com> Co-authored-by: 李枨煊 <chengxuan@staff.weibo.com> Co-authored-by: johnny0120 <jiangyang7@staff.weibo.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
fix(frontend): preserve both images and text when pasting styled content (wecode-ai#888) See merge request weibo_rd/common/wecode/wegent!1064
Feature/knowledge document read (wecode-ai#888) See merge request weibo_rd/common/wecode/wegent!1865
Summary by CodeRabbit
Release Notes
New Features
Improvements
Localization