logs + team parity: pretty step/container renderers; quota + audit on team creation
Two bundled changes:
── LiveRunLogs prettification ──────────────────────────────────
The Steps + Container tabs were plain mono lines with a single
color per event. Now they get structured layout:
Steps:
- Color-hashed actor pill (stable palette so [Distiller] and
[Novelty Analyst] each get their own hue across the session).
- Phase pill (plan=cyan, work=green, synth=amber, aggregate=purple).
- Token count pill formatted 1.2k / 14.3k / etc.
- Gated-action warning pill in amber when > 0.
- Left-border color strip keyed to the actor for at-a-glance
visual grouping.
- Long outputs collapse to their first 300 chars with a '+ N more'
toggle to expand the full text.
- 'done' events get a green (or red for error) border strip +
pill instead of blending into the stream.
Container:
- Splits '[actor] action (outcome) · msg' into colored spans —
actor pill (deterministic color), action in dim, outcome pill
green/red/dim by state.
- Non-line events (info/error/done) get their own left-border
strip so bash echoes and stack traces don't drown in the daemon
chatter.
- Timestamps switch to HH:MM:SS.mmm — dense but scannable.
Small palette (LOG constants) keeps the color budget bounded — no
new UI vocabulary, just cleaner reads of what was already there.
── Team-wizard governance parity ───────────────────────────────
build_team_with_lifecycle now matches POST /api/claws' governance:
- enforce_new_agent quota check per member (previously bypassed
workspace agent quotas entirely for team/auto-provision paths).
- audit::append('agent.created', ..., {source: 'team_wizard'}) per
member so team-created claws appear in the same audit trail as
individually-created ones. Adding a 'source' key distinguishes
provenance without changing consumers.
.brain (h5) handling was already consistent between the two paths —
both use the lazy on-first-access load_brain hook seeded from
agents.system_prompt. No change there.
This commit is contained in:
@@ -96,6 +96,11 @@ pub(crate) async fn build_team_with_lifecycle(
|
||||
|
||||
let mut claw_ids: Vec<Uuid> = Vec::with_capacity(members.len());
|
||||
for m in members {
|
||||
// Parity with the individual `POST /api/claws` handler — each
|
||||
// claw counts against the workspace's agent quota + emits an
|
||||
// audit row. Without these the auto-provision + team-wizard
|
||||
// paths silently bypassed both governance rails.
|
||||
crate::quota::enforce_new_agent(state, workspace_id).await?;
|
||||
let agent = Agent {
|
||||
id: AgentId::new(),
|
||||
workspace_id,
|
||||
@@ -109,6 +114,20 @@ pub(crate) async fn build_team_with_lifecycle(
|
||||
status: AgentStatus::Online,
|
||||
};
|
||||
cm_db::repo::agents::insert(&state.pool, &agent, &AccessPolicy::default()).await?;
|
||||
cm_db::repo::audit::append(
|
||||
&state.pool,
|
||||
workspace_id,
|
||||
cm_db::repo::audit::Actor::User(user_id),
|
||||
"agent.created",
|
||||
"agent",
|
||||
&agent.id.to_string(),
|
||||
serde_json::json!({
|
||||
"name": agent.name,
|
||||
"job_title": agent.job_title,
|
||||
"source": "team_wizard",
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
let claw_id = agent.id.as_uuid();
|
||||
provisioner
|
||||
.provision_claw(claw_id, &m.model)
|
||||
|
||||
Reference in New Issue
Block a user