fix: align calendar API with actual HarborForge.Backend contract
Initial drop guessed the heartbeat shape; sim e2e against a running
harborforge-backend revealed the real contract is per-agent with
header auth, not server-wide with bearer:
POST /calendar/agent/heartbeat
headers: X-Agent-ID, X-Claw-Identifier
body: {claw_identifier, agent_id}
response: {slots: [Slot], agent_status, message?}
PATCH /calendar/slots/{id}/agent-update
PATCH /calendar/slots/virtual/{vid}/agent-update
body: {status, started_at?, actual_duration?}
POST /calendar/agent/status
body: {claw_identifier, agent_id, status}
Refactors:
- internal/calendar/types.go now mirrors OpenclawPlugin/calendar/
types.ts 1:1 (SlotStatus camelCase, real vs virtual slot id
discrimination, event_data shape)
- internal/calendar/bridge.go: header-based auth, per-agent method
signatures, separate UpdateRealSlot vs UpdateVirtualSlot
- internal/calendar/scheduler.go: per-agent heartbeat loop
(one HTTP call per agent per tick), highest-priority slot
selection, agent-update PATCH for terminal/non-terminal states
- SingleActiveAgentID helper for main.bestEffortAgentID
Also fix two bugs found in sim:
- bgCtx capture: AgentLister closures were capturing Init's ctx
which dies the moment MCP initialize returns; switched to
bgCtx (lifetime = plugin process)
- tools.toolRestartStatus referenced a non-existent
sch.RestartPending — HF backend has no restart endpoint per
/openapi.json, so the tool now reports last_heartbeats freshness
Scheduler logs each tick + each heartbeat outcome at info so
operators can see backend connectivity without enabling debug.
E2E against http://harborforge-backend:8000 in sim:
daemon → heartbeat → 404 "Agent not found"
(= correct endpoint, correct headers, correct body — agent just
isn't registered yet, which is expected for an untenanted
plugin)
This commit is contained in:
@@ -176,11 +176,15 @@ func toolCalendarResume(ctx context.Context, deps Deps) (sdkplugin.ToolResult, e
|
||||
}
|
||||
|
||||
func toolRestartStatus(deps Deps) (sdkplugin.ToolResult, error) {
|
||||
// HarborForge backend doesn't expose a restart-pending endpoint
|
||||
// (verified via /openapi.json) so we report the most recent
|
||||
// heartbeat freshness instead. Useful for operators sanity-
|
||||
// checking that the plugin's calendar loop is still alive.
|
||||
sch := deps.Scheduler.Status()
|
||||
return jsonResult(map[string]any{
|
||||
"pending": sch.RestartPending,
|
||||
"last_heartbeat": sch.LastHeartbeat,
|
||||
"observed_at": time.Now().UTC(),
|
||||
"pending": false,
|
||||
"last_heartbeats": sch.LastHeartbeats,
|
||||
"observed_at": time.Now().UTC(),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user