Add multi-user automation features and per-user error tracking. - Database migrations: add workflow_configs/workflow_runs (004), app_errors (005), pipeline_configs/pipeline_runs (006), and add user_token_hash to app_errors (007). - Backend: introduce per-request token handling (X-API-Token) via app.api.deps and update many API routes (auth, automations, bank, characters, dashboard, events, exchange, logs) to use user-scoped Artifacts client and character scoping. Auth endpoints no longer store tokens server-side (validate-only); clear is a no-op on server. - New Errors API and services: endpoint to list, filter, resolve, and report errors scoped to the requesting user; add error models, schemas, middleware/error handler and error_service for recording/hashing tokens. - Pipelines & Workflows: add API routers, models, schemas and engine modules (pipeline/worker/coordinator, workflow runner/conditions) and action_executor updates to support workflow/pipeline execution. - Logs: logs endpoint now prefers fetching recent action logs from the game API (with fallback to local DB), supports paging and filtering, and scopes results to the user. - Frontend: add pipeline/workflow builders, lists, progress components and hooks (use-errors, use-pipelines, use-workflows), sentry client config, and updates to API client/constants/types. - Misc: add middleware error handler, various engine strategy tweaks, tests adjusted. Overall this change enables per-user API tokens, scopes DB queries to each user, introduces pipelines/workflows runtime support, and centralizes application error tracking.
146 lines
4.3 KiB
Python
146 lines
4.3 KiB
Python
from datetime import datetime
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Transition conditions
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TransitionConditionSchema(BaseModel):
|
|
"""Defines when a workflow step should transition to the next step."""
|
|
|
|
type: str = Field(
|
|
...,
|
|
description=(
|
|
"Condition type: strategy_complete, loops_completed, inventory_full, "
|
|
"inventory_item_count, bank_item_count, skill_level, gold_amount, "
|
|
"actions_count, timer"
|
|
),
|
|
)
|
|
operator: str = Field(
|
|
default=">=",
|
|
description="Comparison operator: >=, <=, ==, >, <",
|
|
)
|
|
value: int = Field(
|
|
default=0,
|
|
description="Target value for the condition",
|
|
)
|
|
item_code: str = Field(
|
|
default="",
|
|
description="Item code (for inventory_item_count, bank_item_count)",
|
|
)
|
|
skill: str = Field(
|
|
default="",
|
|
description="Skill name (for skill_level condition)",
|
|
)
|
|
seconds: int = Field(
|
|
default=0,
|
|
ge=0,
|
|
description="Duration in seconds (for timer condition)",
|
|
)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Workflow steps
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class WorkflowStepSchema(BaseModel):
|
|
"""A single step within a workflow pipeline."""
|
|
|
|
id: str = Field(..., description="Unique step identifier (e.g. 'step_1')")
|
|
name: str = Field(..., min_length=1, max_length=100, description="Human-readable step name")
|
|
strategy_type: str = Field(
|
|
...,
|
|
description="Strategy type: combat, gathering, crafting, trading, task, leveling",
|
|
)
|
|
config: dict = Field(default_factory=dict, description="Strategy-specific configuration")
|
|
transition: TransitionConditionSchema | None = Field(
|
|
default=None,
|
|
description="Condition to advance to the next step (None = run until strategy completes)",
|
|
)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Request schemas
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class WorkflowConfigCreate(BaseModel):
|
|
name: str = Field(..., min_length=1, max_length=100)
|
|
character_name: str = Field(..., min_length=1, max_length=100)
|
|
description: str = Field(default="")
|
|
steps: list[WorkflowStepSchema] = Field(..., min_length=1)
|
|
loop: bool = Field(default=False)
|
|
max_loops: int = Field(default=0, ge=0)
|
|
|
|
|
|
class WorkflowConfigUpdate(BaseModel):
|
|
name: str | None = Field(default=None, min_length=1, max_length=100)
|
|
description: str | None = None
|
|
steps: list[WorkflowStepSchema] | None = Field(default=None, min_length=1)
|
|
loop: bool | None = None
|
|
max_loops: int | None = Field(default=None, ge=0)
|
|
enabled: bool | None = None
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Response schemas
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class WorkflowConfigResponse(BaseModel):
|
|
id: int
|
|
name: str
|
|
character_name: str
|
|
description: str
|
|
steps: list[dict]
|
|
loop: bool
|
|
max_loops: int
|
|
enabled: bool
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
|
|
model_config = {"from_attributes": True}
|
|
|
|
|
|
class WorkflowRunResponse(BaseModel):
|
|
id: int
|
|
workflow_id: int
|
|
status: str
|
|
current_step_index: int
|
|
current_step_id: str
|
|
loop_count: int
|
|
total_actions_count: int
|
|
step_actions_count: int
|
|
started_at: datetime
|
|
stopped_at: datetime | None = None
|
|
error_message: str | None = None
|
|
step_history: list[dict] = Field(default_factory=list)
|
|
|
|
model_config = {"from_attributes": True}
|
|
|
|
|
|
class WorkflowStatusResponse(BaseModel):
|
|
workflow_id: int
|
|
character_name: str
|
|
status: str
|
|
run_id: int | None = None
|
|
current_step_index: int = 0
|
|
current_step_id: str = ""
|
|
total_steps: int = 0
|
|
loop_count: int = 0
|
|
total_actions_count: int = 0
|
|
step_actions_count: int = 0
|
|
strategy_state: str = ""
|
|
|
|
model_config = {"from_attributes": True}
|
|
|
|
|
|
class WorkflowConfigDetailResponse(BaseModel):
|
|
"""Workflow config with its run history."""
|
|
|
|
config: WorkflowConfigResponse
|
|
runs: list[WorkflowRunResponse] = Field(default_factory=list)
|