feat: reorder properties in various interfaces for improved consistency and readability

This commit is contained in:
Abhimanyu Saharan
2026-02-06 21:56:16 +05:30
parent bc6345978d
commit 5611f8eb67
68 changed files with 3424 additions and 3014 deletions

View File

@@ -227,12 +227,14 @@ async def create_task_comment(
@router.get("/boards/{board_id}/memory", response_model=DefaultLimitOffsetPage[BoardMemoryRead])
async def list_board_memory(
is_chat: bool | None = Query(default=None),
board: Board = Depends(get_board_or_404),
session: AsyncSession = Depends(get_session),
agent_ctx: AgentAuthContext = Depends(get_agent_auth_context),
) -> DefaultLimitOffsetPage[BoardMemoryRead]:
_guard_board_access(agent_ctx, board)
return await board_memory_api.list_board_memory(
is_chat=is_chat,
board=board,
session=session,
actor=_actor(agent_ctx),

View File

@@ -5,6 +5,7 @@ import re
from uuid import uuid4
from fastapi import APIRouter, Depends, HTTPException, status
from pydantic import ValidationError
from sqlmodel import col, select
from sqlmodel.ext.asyncio.session import AsyncSession
@@ -25,8 +26,10 @@ from app.schemas.board_onboarding import (
BoardOnboardingAgentComplete,
BoardOnboardingAgentUpdate,
BoardOnboardingConfirm,
BoardOnboardingLeadAgentDraft,
BoardOnboardingRead,
BoardOnboardingStart,
BoardOnboardingUserProfile,
)
from app.schemas.boards import BoardRead
from app.services.agent_provisioning import DEFAULT_HEARTBEAT_CONFIG, provision_agent
@@ -65,6 +68,9 @@ async def _ensure_lead_agent(
gateway: Gateway,
config: GatewayClientConfig,
auth: AuthContext,
*,
agent_name: str | None = None,
identity_profile: dict[str, str] | None = None,
) -> Agent:
existing = (
await session.exec(
@@ -74,24 +80,31 @@ async def _ensure_lead_agent(
)
).first()
if existing:
if existing.name != _lead_agent_name(board):
existing.name = _lead_agent_name(board)
desired_name = agent_name or _lead_agent_name(board)
if existing.name != desired_name:
existing.name = desired_name
session.add(existing)
await session.commit()
await session.refresh(existing)
return existing
merged_identity_profile = {
"role": "Board Lead",
"communication_style": "direct, concise, practical",
"emoji": ":gear:",
}
if identity_profile:
merged_identity_profile.update(
{key: value.strip() for key, value in identity_profile.items() if value.strip()}
)
agent = Agent(
name=_lead_agent_name(board),
name=agent_name or _lead_agent_name(board),
status="provisioning",
board_id=board.id,
is_board_lead=True,
heartbeat_config=DEFAULT_HEARTBEAT_CONFIG.copy(),
identity_profile={
"role": "Board Lead",
"communication_style": "direct, concise, practical",
"emoji": ":gear:",
},
identity_profile=merged_identity_profile,
)
raw_token = generate_agent_token()
agent.agent_token_hash = hash_agent_token(raw_token)
@@ -162,7 +175,11 @@ async def start_onboarding(
prompt = (
"BOARD ONBOARDING REQUEST\n\n"
f"Board Name: {board.name}\n"
"You are the main agent. Ask the user 3-6 focused questions to clarify their goal.\n"
"You are the main agent. Ask the user 6-10 focused questions total:\n"
"- 3-6 questions to clarify the board goal.\n"
"- 1 question to choose a unique name for the board lead agent (first-name style).\n"
"- 2-4 questions to capture the user's preferences for how the board lead should work\n"
" (communication style, autonomy, update cadence, and output formatting).\n"
"Do NOT respond in OpenClaw chat.\n"
"All onboarding responses MUST be sent to Mission Control via API.\n"
f"Mission Control base URL: {base_url}\n"
@@ -178,13 +195,19 @@ async def start_onboarding(
f'curl -s -X POST "{base_url}/api/v1/agent/boards/{board.id}/onboarding" '
'-H "X-Agent-Token: $AUTH_TOKEN" '
'-H "Content-Type: application/json" '
'-d \'{"status":"complete","board_type":"goal","objective":"...","success_metrics":{...},"target_date":"YYYY-MM-DD"}\'\n'
'-d \'{"status":"complete","board_type":"goal","objective":"...","success_metrics":{"metric":"...","target":"..."},"target_date":"YYYY-MM-DD","user_profile":{"preferred_name":"...","pronouns":"...","timezone":"...","notes":"...","context":"..."},"lead_agent":{"name":"Ava","identity_profile":{"role":"Board Lead","communication_style":"direct, concise, practical","emoji":":gear:"},"autonomy_level":"balanced","verbosity":"concise","output_format":"bullets","update_cadence":"daily","custom_instructions":"..."}}\'\n'
"ENUMS:\n"
"- board_type: goal | general\n"
"- lead_agent.autonomy_level: ask_first | balanced | autonomous\n"
"- lead_agent.verbosity: concise | balanced | detailed\n"
"- lead_agent.output_format: bullets | mixed | narrative\n"
"- lead_agent.update_cadence: asap | hourly | daily | weekly\n"
"QUESTION FORMAT (one question per response, no arrays, no markdown, no extra text):\n"
'{"question":"...","options":[{"id":"1","label":"..."},{"id":"2","label":"..."}]}\n'
"Do NOT wrap questions in a list. Do NOT add commentary.\n"
"When you have enough info, return JSON ONLY (via API):\n"
'{"status":"complete","board_type":"goal"|"general","objective":"...",'
'"success_metrics":{...},"target_date":"YYYY-MM-DD"}.'
"When you have enough info, send one final response with status=complete.\n"
"The completion payload must include board_type. If board_type=goal, include objective + success_metrics.\n"
"Also include user_profile + lead_agent to configure the board lead's working style.\n"
)
try:
@@ -337,10 +360,71 @@ async def confirm_onboarding(
onboarding.status = "confirmed"
onboarding.updated_at = utcnow()
user_profile: BoardOnboardingUserProfile | None = None
lead_agent: BoardOnboardingLeadAgentDraft | None = None
if isinstance(onboarding.draft_goal, dict):
raw_profile = onboarding.draft_goal.get("user_profile")
if raw_profile is not None:
try:
user_profile = BoardOnboardingUserProfile.model_validate(raw_profile)
except ValidationError:
user_profile = None
raw_lead = onboarding.draft_goal.get("lead_agent")
if raw_lead is not None:
try:
lead_agent = BoardOnboardingLeadAgentDraft.model_validate(raw_lead)
except ValidationError:
lead_agent = None
if auth.user and user_profile:
changed = False
if user_profile.preferred_name is not None:
auth.user.preferred_name = user_profile.preferred_name
changed = True
if user_profile.pronouns is not None:
auth.user.pronouns = user_profile.pronouns
changed = True
if user_profile.timezone is not None:
auth.user.timezone = user_profile.timezone
changed = True
if user_profile.notes is not None:
auth.user.notes = user_profile.notes
changed = True
if user_profile.context is not None:
auth.user.context = user_profile.context
changed = True
if changed:
session.add(auth.user)
lead_identity_profile: dict[str, str] = {}
lead_name: str | None = None
if lead_agent:
lead_name = lead_agent.name
if lead_agent.identity_profile:
lead_identity_profile.update(lead_agent.identity_profile)
if lead_agent.autonomy_level:
lead_identity_profile["autonomy_level"] = lead_agent.autonomy_level
if lead_agent.verbosity:
lead_identity_profile["verbosity"] = lead_agent.verbosity
if lead_agent.output_format:
lead_identity_profile["output_format"] = lead_agent.output_format
if lead_agent.update_cadence:
lead_identity_profile["update_cadence"] = lead_agent.update_cadence
if lead_agent.custom_instructions:
lead_identity_profile["custom_instructions"] = lead_agent.custom_instructions
gateway, config = await _gateway_config(session, board)
session.add(board)
session.add(onboarding)
await session.commit()
await session.refresh(board)
await _ensure_lead_agent(session, board, gateway, config, auth)
await _ensure_lead_agent(
session,
board,
gateway,
config,
auth,
agent_name=lead_name,
identity_profile=lead_identity_profile or None,
)
return board