Large World graph, agent platform, brain stack & dashboard rebuild
Frontend - Large World: collapse org/company/team tiers into one expandable React Flow hierarchy (WorldFlow) with per-click expand, persisted node positions, a compact tree sidebar, wrench multi-select delete across levels, and a sized right slide-out (phone/tablet/full) showing an agent summary + drill button. - Agent page: GitHub-style animated contribution grid (VitalsCard), collapsible System Prompt + Personality cards, restructured anatomy cards, bigger avatar with name/title header row, Markdown/JSON-aware rendering, brain registry + history, avatar generate/upload. - User-icon menu (Infrastructure/Brains/Tools/Profile/Credits) + ToolPanel; Master Planner deploy wizard (Specialists/Swarm/Scheduled/Triggered); Team Runs view; reap-progress modal; dashboard is the single live interface. Backend - cm-brain crate (.brain as the agent definition) + brain apply/history. - Hard-purge reap (FK-ordered) + sandbox release + SSE batch-delete. - Swarm self-verifying loop, mode-aware planner, web.search tool, webhooks (migration 0013), org/company/team delete endpoints, scheduler sweeps. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
9f266d5806
commit
34f744734b
@@ -3,7 +3,7 @@
|
||||
//! drives a REAL run through the runtime in the routine's dedicated
|
||||
//! session — gated tools inside a routine still hit the approval queue.
|
||||
|
||||
use cm_db::repo::{agents, routine_runs, routines, sessions};
|
||||
use cm_db::repo::{agents, routine_runs, routines, sessions, teams, topology_runs};
|
||||
use cm_runtime::Runtime;
|
||||
use sqlx::PgPool;
|
||||
use time::OffsetDateTime;
|
||||
@@ -33,18 +33,59 @@ impl Scheduler {
|
||||
pub async fn tick(&self, now: OffsetDateTime) -> Result<usize, ScheduleError> {
|
||||
let due = routines::claim_due(&self.pool, now).await?;
|
||||
for routine in &due {
|
||||
// Reschedule first: a firing failure must not stall the clock.
|
||||
let next = next_occurrence(&routine.schedule_cron, now).ok();
|
||||
// Reschedule first: a firing failure must not stall the clock. A
|
||||
// one-shot routine (Scheduled mode, a specific date/time) fires once
|
||||
// and never reschedules.
|
||||
let one_shot = routine.action.get("one_shot").and_then(|v| v.as_bool()).unwrap_or(false);
|
||||
let next = if one_shot { None } else { next_occurrence(&routine.schedule_cron, now).ok() };
|
||||
routines::set_next_run(&self.pool, routine.id, next).await?;
|
||||
|
||||
let agent_id = cm_domain::AgentId::from(routine.agent_id);
|
||||
let Ok(agent) = agents::get(&self.pool, agent_id).await else {
|
||||
continue; // deleted agent: routine is orphaned
|
||||
};
|
||||
|
||||
// Topology routine: fire the whole team's stored topology as one
|
||||
// durable run (the entire team loops, not just the coordinator).
|
||||
if let Some(topo) = routine.action.get("topology") {
|
||||
let team_id = topo
|
||||
.get("team_id")
|
||||
.and_then(|v| v.as_str())
|
||||
.and_then(|s| s.parse::<uuid::Uuid>().ok());
|
||||
let task = topo
|
||||
.get("task")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or(routine.name.as_str());
|
||||
let run_id = routine_runs::start(&self.pool, routine.id).await.ok();
|
||||
let res: Result<(), String> = match team_id {
|
||||
Some(tid) => match teams::get_team(&self.pool, tid, agent.workspace_id).await {
|
||||
Ok(team) => topology_runs::enqueue_run(
|
||||
&self.pool,
|
||||
uuid::Uuid::now_v7(),
|
||||
agent.workspace_id,
|
||||
task,
|
||||
&team.graph,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| e.to_string()),
|
||||
Err(e) => Err(e.to_string()),
|
||||
},
|
||||
None => Err("routine topology action missing team_id".to_string()),
|
||||
};
|
||||
if let Some(rid) = run_id {
|
||||
let (status, err) = match &res {
|
||||
Ok(_) => ("ok", None),
|
||||
Err(e) => ("error", Some(e.clone())),
|
||||
};
|
||||
let _ = routine_runs::finish(&self.pool, rid, status, err.as_deref()).await;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
let message = routine.action["message"].as_str().unwrap_or_default();
|
||||
if message.is_empty() {
|
||||
continue;
|
||||
}
|
||||
let agent_id = cm_domain::AgentId::from(routine.agent_id);
|
||||
let Ok(agent) = agents::get(&self.pool, agent_id).await else {
|
||||
continue; // deleted agent: routine is orphaned
|
||||
};
|
||||
|
||||
// Each routine runs in one dedicated, recognizable session.
|
||||
let title = format!("⏰ {}", routine.name);
|
||||
|
||||
Reference in New Issue
Block a user