Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
676783b
docs(wework): add runtime work item design
qdaxb Jun 20, 2026
f8e5abc
Merge remote-tracking branch 'origin/main' into HEAD
qdaxb Jun 20, 2026
e5232e1
fix: update doc
qdaxb Jun 20, 2026
a9983d4
feat(wework): use runtime local tasks
qdaxb Jun 20, 2026
934db45
fix(backend): avoid db task coupling in runtime work
qdaxb Jun 20, 2026
77865c7
fix(wework): keep runtime worklists device-sourced
qdaxb Jun 20, 2026
db87bd5
test(wework): address runtime sidebar review notes
qdaxb Jun 20, 2026
f33f766
feat(wework): complete runtime local task workflow
qdaxb Jun 21, 2026
586a245
fix(runtime-work): address PR review and CI failures
qdaxb Jun 21, 2026
a44d4f1
Merge branch 'main' into codex/runtime-session-workitems
qdaxb Jun 21, 2026
776607e
[codex] Support Wework runtime task transfer (#1506)
qdaxb Jun 21, 2026
4f24dca
fix(runtime): notify native tasks and resolve workspace tools
qdaxb Jun 21, 2026
ae1f0b5
feat(runtime): refine local work project setup
qdaxb Jun 21, 2026
769bf14
fix(runtime): address ci and review findings
qdaxb Jun 21, 2026
2f9c1c4
test(backend): update fork history resolver mocks
qdaxb Jun 21, 2026
9639fe5
fix(im): notify runtime tasks on completion
qdaxb Jun 21, 2026
3035e59
Refactor task runtime state handling and frontend sync
qdaxb Jun 21, 2026
2780c23
fix(runtime): reuse project workspace binding for fork
qdaxb Jun 21, 2026
eeedbcc
style(backend): format runtime work hooks
qdaxb Jun 21, 2026
e804e62
docs(runtime): describe fork workspace transfer
qdaxb Jun 21, 2026
99baa2e
feat(wework): filter sidebar tasks by device
qdaxb Jun 21, 2026
c92ddec
fix(wework): use sidebar tokens for project action
qdaxb Jun 21, 2026
18ae6da
feat(wework): add device startup hint
qdaxb Jun 21, 2026
f477317
fix(runtime): fork git workspace without archive transfer
qdaxb Jun 21, 2026
5e133f9
fix(wework): hide source device in task fork dialog
qdaxb Jun 21, 2026
a666de8
fix(wework): keep subscribed task notification visible
qdaxb Jun 21, 2026
6d53cb5
fix(runtime): sync forked codex task state
qdaxb Jun 21, 2026
2ab9423
fix(runtime): preserve fork and terminal workspace context
qdaxb Jun 21, 2026
88460b5
fix(runtime): address PR CI failures
qdaxb Jun 21, 2026
8a768d8
test(backend): align IM interaction fake with runtime task continuation
qdaxb Jun 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ Wegent is an open-source AI-native operating system for defining, organizing, an
- English version: [`docs/en/developer-guide/sandbox-workspace-archive.md`](docs/en/developer-guide/sandbox-workspace-archive.md)
- Shared skill directory (unify Claude and Codex local skills under `~/.agents/skills`): [`docs/zh/developer-guide/shared-skill-directory.md`](docs/zh/developer-guide/shared-skill-directory.md)
- English version: [`docs/en/developer-guide/shared-skill-directory.md`](docs/en/developer-guide/shared-skill-directory.md)
- Runtime local work (Project -> Device Workspace -> LocalTask without DB task rows): [`docs/zh/developer-guide/runtime-local-work.md`](docs/zh/developer-guide/runtime-local-work.md)
- English version: [`docs/en/developer-guide/runtime-local-work.md`](docs/en/developer-guide/runtime-local-work.md)

**📚 Documentation Writing Rules:**
- All documentation files MUST include frontmatter with `sidebar_position` for ordering:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
"""add device workspaces

Revision ID: f1a2b3c4d5e6
Revises: d5e6f7a8b9c0
Create Date: 2026-06-20 00:00:00.000000

"""

from typing import Sequence, Union

import sqlalchemy as sa

from alembic import op

# revision identifiers, used by Alembic.
revision: str = "f1a2b3c4d5e6"
down_revision: Union[str, Sequence[str], None] = "d5e6f7a8b9c0"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
op.create_table(
"device_workspaces",
sa.Column("id", sa.Integer(), nullable=False, comment="Primary key"),
sa.Column("user_id", sa.Integer(), nullable=False, comment="Owner user ID"),
sa.Column("project_id", sa.Integer(), nullable=False, comment="Project ID"),
sa.Column(
"device_id", sa.String(length=128), nullable=False, comment="Device ID"
),
sa.Column(
"workspace_path",
sa.Text(),
nullable=False,
comment="Absolute workspace path on the local device",
),
sa.Column(
"workspace_path_hash",
sa.String(length=64),
nullable=False,
comment="SHA-256 hash of workspace_path for MySQL-safe uniqueness",
),
sa.Column(
"repo_url", sa.Text(), nullable=True, comment="Optional repository URL"
),
sa.Column(
"repo_root_fingerprint",
sa.String(length=128),
nullable=True,
comment="Optional local repository root fingerprint",
),
sa.Column(
"label",
sa.String(length=255),
nullable=True,
comment="User-facing workspace label",
),
sa.Column(
"last_seen_at",
sa.DateTime(),
nullable=True,
comment="Last time the owning executor reported this workspace",
),
sa.Column(
"created_at",
sa.DateTime(),
nullable=False,
server_default=sa.func.now(),
comment="Creation timestamp",
),
sa.Column(
"updated_at",
sa.DateTime(),
nullable=False,
server_default=sa.func.now(),
comment="Last update timestamp",
),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint(
"user_id",
"device_id",
"workspace_path_hash",
name="uq_device_workspace_user_device_path",
),
mysql_charset="utf8mb4",
mysql_collate="utf8mb4_unicode_ci",
mysql_engine="InnoDB",
comment="Central mappings from Projects to device-local workspaces",
)
op.create_index(
op.f("ix_device_workspaces_id"), "device_workspaces", ["id"], unique=False
)
op.create_index(
op.f("ix_device_workspaces_user_id"),
"device_workspaces",
["user_id"],
unique=False,
)
op.create_index(
op.f("ix_device_workspaces_project_id"),
"device_workspaces",
["project_id"],
unique=False,
)
op.create_index(
op.f("ix_device_workspaces_device_id"),
"device_workspaces",
["device_id"],
unique=False,
)


def downgrade() -> None:
op.drop_index(
op.f("ix_device_workspaces_device_id"), table_name="device_workspaces"
)
op.drop_index(
op.f("ix_device_workspaces_project_id"), table_name="device_workspaces"
)
op.drop_index(op.f("ix_device_workspaces_user_id"), table_name="device_workspaces")
op.drop_index(op.f("ix_device_workspaces_id"), table_name="device_workspaces")
op.drop_table("device_workspaces")
4 changes: 2 additions & 2 deletions backend/app/api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
knowledge,
knowledge_open,
knowledge_transfer,
local_codex,
local_executor,
mcp_providers,
oidc,
Expand All @@ -28,6 +27,7 @@
prompt_optimization,
quota,
repository,
runtime_work,
share,
skill_identity,
skill_market,
Expand Down Expand Up @@ -230,7 +230,7 @@
local_executor.router, prefix="/local-executor", tags=["local-executor"]
)
api_router.include_router(
local_codex.router, prefix="/local-codex", tags=["local-codex"]
runtime_work.router, prefix="/runtime-work", tags=["runtime-work"]
)

api_router.include_router(utils.router, prefix="/utils", tags=["utils"])
Expand Down
26 changes: 0 additions & 26 deletions backend/app/api/endpoints/adapter/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,6 @@
from app.services import prompt_draft_service
from app.services.adapters.executor_job import job_service
from app.services.adapters.task_kinds import task_kinds_service
from app.services.adapters.wework_conversation_search import (
search_wework_conversation_tasks,
)
from app.services.chat.storage import session_manager
from app.services.remote_workspace_service import remote_workspace_service
from app.services.shared_task import shared_task_service
Expand Down Expand Up @@ -281,29 +278,6 @@ def search_tasks_by_title(
return {"total": total, "items": items}


@router.get("/wework/conversation-search", response_model=TaskListResponse)
def search_wework_conversation_task_list(
keyword: str = Query(
..., min_length=1, description="Search by task title or message keywords"
),
page: int = Query(1, ge=1, description="Page number"),
limit: int = Query(10, ge=1, le=100, description="Items per page"),
current_user: User = Depends(security.get_current_user),
db: Session = Depends(get_db),
):
"""Search WeWork conversations by title or conversation content."""
skip = (page - 1) * limit
items, total = search_wework_conversation_tasks(
db=db,
user_id=current_user.id,
keyword=keyword,
skip=skip,
limit=limit,
client_origin=CLIENT_ORIGIN_WEWORK,
)
return {"total": total, "items": items}


@router.get("/archived", response_model=ArchivedTaskListResponse)
def get_archived_tasks(
page: int = Query(1, ge=1, description="Page number"),
Expand Down
Loading
Loading