Compare commits
32 Commits
feat/get-a
...
6fd37ab46d
| Author | SHA1 | Date | |
|---|---|---|---|
| 6fd37ab46d | |||
|
|
a0b3380654 | ||
| b8e413a7ea | |||
|
|
d41d12aecd | ||
| a1049492e1 | |||
|
|
8f3c69032f | ||
| d870646e28 | |||
|
|
2cbf6445eb | ||
| 4675ab7201 | |||
| a9d075bc19 | |||
| 9429e37542 | |||
| 0229fbb54c | |||
| ffce4298c8 | |||
| a115e380cb | |||
| 94155614f5 | |||
| 90b494f097 | |||
| e7d3cbe07b | |||
| 51fb8ca073 | |||
| 1cb924451b | |||
| c011e334a0 | |||
| d52861fd9c | |||
| 3aa6dd2d6e | |||
| c3199d0cd0 | |||
| d3f72962c0 | |||
| 4643a73c60 | |||
| eae947d9b6 | |||
| a2f626557e | |||
| c5827db872 | |||
| 7326cadfec | |||
| 1b10c97099 | |||
| 8434a5d226 | |||
| a2ab541b73 |
@@ -52,7 +52,6 @@ from app.schemas.calendar import (
|
|||||||
)
|
)
|
||||||
from app.services.agent_heartbeat import get_pending_slots_for_agent
|
from app.services.agent_heartbeat import get_pending_slots_for_agent
|
||||||
from app.services.agent_status import (
|
from app.services.agent_status import (
|
||||||
AgentStatusError,
|
|
||||||
record_heartbeat,
|
record_heartbeat,
|
||||||
transition_to_busy,
|
transition_to_busy,
|
||||||
transition_to_idle,
|
transition_to_idle,
|
||||||
@@ -562,29 +561,6 @@ def agent_update_virtual_slot(
|
|||||||
return TimeSlotEditResponse(slot=_slot_to_response(slot), warnings=[])
|
return TimeSlotEditResponse(slot=_slot_to_response(slot), warnings=[])
|
||||||
|
|
||||||
|
|
||||||
@router.get(
|
|
||||||
"/agent/status",
|
|
||||||
summary="Read an agent's current runtime status (no side effects)",
|
|
||||||
)
|
|
||||||
def get_agent_status(
|
|
||||||
agent_id: str = Query(..., description="Target agent_id"),
|
|
||||||
x_claw_identifier: str = Header(..., alias="X-Claw-Identifier"),
|
|
||||||
db: Session = Depends(get_db),
|
|
||||||
):
|
|
||||||
"""Return `{agent_id, status}` so callers (Fabric.OpenclawPlugin's
|
|
||||||
triage on-call gate, etc.) can decide whether the agent is currently
|
|
||||||
eligible without flipping their state.
|
|
||||||
|
|
||||||
No-op for unknown agents — returns 404 with `{detail: 'Agent not
|
|
||||||
found'}` so the caller can decide whether to fail-open or fail-closed.
|
|
||||||
"""
|
|
||||||
agent = _require_agent(db, agent_id, x_claw_identifier)
|
|
||||||
return {
|
|
||||||
"agent_id": agent.agent_id,
|
|
||||||
"status": agent.status.value if hasattr(agent.status, 'value') else str(agent.status),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@router.post(
|
@router.post(
|
||||||
"/agent/status",
|
"/agent/status",
|
||||||
summary="Update agent runtime status from plugin",
|
summary="Update agent runtime status from plugin",
|
||||||
@@ -595,31 +571,19 @@ def update_agent_status(
|
|||||||
):
|
):
|
||||||
agent = _require_agent(db, payload.agent_id, payload.claw_identifier)
|
agent = _require_agent(db, payload.agent_id, payload.claw_identifier)
|
||||||
target = (payload.status or '').lower().strip()
|
target = (payload.status or '').lower().strip()
|
||||||
# Idempotent same-state transition: a 'busy → busy' request is a
|
if target == AgentStatus.IDLE.value:
|
||||||
# no-op rather than a 500. Lets plugin status gates / cli `--set`
|
transition_to_idle(db, agent)
|
||||||
# be safe to fire-and-forget without first reading current state.
|
elif target == AgentStatus.BUSY.value:
|
||||||
current = agent.status.value if hasattr(agent.status, 'value') else str(agent.status)
|
transition_to_busy(db, agent, slot_type=SlotType.WORK)
|
||||||
if current == target:
|
elif target == AgentStatus.ON_CALL.value:
|
||||||
return {"ok": True, "agent_id": agent.agent_id, "status": current, "no_change": True}
|
transition_to_busy(db, agent, slot_type=SlotType.ON_CALL)
|
||||||
try:
|
elif target == AgentStatus.OFFLINE.value:
|
||||||
if target == AgentStatus.IDLE.value:
|
transition_to_offline(db, agent)
|
||||||
transition_to_idle(db, agent)
|
elif target == AgentStatus.EXHAUSTED.value:
|
||||||
elif target == AgentStatus.BUSY.value:
|
reason = ExhaustReason.BILLING if payload.exhaust_reason == 'billing' else ExhaustReason.RATE_LIMIT
|
||||||
transition_to_busy(db, agent, slot_type=SlotType.WORK)
|
transition_to_exhausted(db, agent, reason=reason, recovery_at=payload.recovery_at)
|
||||||
elif target == AgentStatus.ON_CALL.value:
|
else:
|
||||||
transition_to_busy(db, agent, slot_type=SlotType.ON_CALL)
|
raise HTTPException(status_code=400, detail="Unsupported agent status")
|
||||||
elif target == AgentStatus.OFFLINE.value:
|
|
||||||
transition_to_offline(db, agent)
|
|
||||||
elif target == AgentStatus.EXHAUSTED.value:
|
|
||||||
reason = ExhaustReason.BILLING if payload.exhaust_reason == 'billing' else ExhaustReason.RATE_LIMIT
|
|
||||||
transition_to_exhausted(db, agent, reason=reason, recovery_at=payload.recovery_at)
|
|
||||||
else:
|
|
||||||
raise HTTPException(status_code=400, detail="Unsupported agent status")
|
|
||||||
except AgentStatusError as e:
|
|
||||||
# State-machine violation (e.g. busy → busy via wrong precondition)
|
|
||||||
# → 409 with the rejected transition explained, instead of a 500.
|
|
||||||
db.rollback()
|
|
||||||
raise HTTPException(status_code=409, detail=str(e))
|
|
||||||
db.commit()
|
db.commit()
|
||||||
return {"ok": True, "agent_id": agent.agent_id, "status": agent.status.value if hasattr(agent.status, 'value') else str(agent.status)}
|
return {"ok": True, "agent_id": agent.agent_id, "status": agent.status.value if hasattr(agent.status, 'value') else str(agent.status)}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user