generated from nhcarrigan/template
feat: display per-agent model override in agent monitor tree
Parse the model field from Agent/Task tool input and surface it in the agent monitor panel as a purple subtitle, so users can immediately see which agents are running on a non-default model. Closes #207
This commit is contained in:
@@ -292,6 +292,8 @@ pub struct AgentStartEvent {
|
|||||||
pub conversation_id: Option<String>,
|
pub conversation_id: Option<String>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub parent_tool_use_id: Option<String>,
|
pub parent_tool_use_id: Option<String>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub model: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
|||||||
@@ -1301,14 +1301,19 @@ fn process_json_line(
|
|||||||
.and_then(|v| v.as_str())
|
.and_then(|v| v.as_str())
|
||||||
.unwrap_or("unknown")
|
.unwrap_or("unknown")
|
||||||
.to_string();
|
.to_string();
|
||||||
|
let model = input
|
||||||
|
.get("model")
|
||||||
|
.and_then(|v| v.as_str())
|
||||||
|
.filter(|s| !s.is_empty())
|
||||||
|
.map(|s| s.to_string());
|
||||||
let now = SystemTime::now()
|
let now = SystemTime::now()
|
||||||
.duration_since(UNIX_EPOCH)
|
.duration_since(UNIX_EPOCH)
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.as_millis() as u64;
|
.as_millis() as u64;
|
||||||
|
|
||||||
tracing::debug!(
|
tracing::debug!(
|
||||||
"Emitting agent-start: id={}, desc={}, type={}, parent={:?}",
|
"Emitting agent-start: id={}, desc={}, type={}, model={:?}, parent={:?}",
|
||||||
id, description, subagent_type, parent_tool_use_id
|
id, description, subagent_type, model, parent_tool_use_id
|
||||||
);
|
);
|
||||||
|
|
||||||
let _ = app.emit(
|
let _ = app.emit(
|
||||||
@@ -1318,6 +1323,7 @@ fn process_json_line(
|
|||||||
agent_id: None, // Will be updated when SubagentStart hook is received
|
agent_id: None, // Will be updated when SubagentStart hook is received
|
||||||
description,
|
description,
|
||||||
subagent_type,
|
subagent_type,
|
||||||
|
model,
|
||||||
started_at: now,
|
started_at: now,
|
||||||
conversation_id: conversation_id.clone(),
|
conversation_id: conversation_id.clone(),
|
||||||
parent_tool_use_id: parent_tool_use_id.clone(),
|
parent_tool_use_id: parent_tool_use_id.clone(),
|
||||||
|
|||||||
@@ -309,6 +309,13 @@
|
|||||||
{agent.description}
|
{agent.description}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<!-- Model override badge -->
|
||||||
|
{#if agent.model}
|
||||||
|
<p class="mt-0.5 text-[10px] text-purple-400 truncate" title="Model: {agent.model}">
|
||||||
|
✦ {agent.model}
|
||||||
|
</p>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<!-- Status indicator -->
|
<!-- Status indicator -->
|
||||||
<div class="mt-1 flex items-center gap-1">
|
<div class="mt-1 flex items-center gap-1">
|
||||||
{#if agent.status === "running"}
|
{#if agent.status === "running"}
|
||||||
|
|||||||
@@ -43,6 +43,22 @@ describe("agents store", () => {
|
|||||||
expect(agents[0]).toMatchObject(agent);
|
expect(agents[0]).toMatchObject(agent);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("preserves model field when provided", () => {
|
||||||
|
const agent = createMockAgent({ model: "claude-opus-4-6" });
|
||||||
|
agentStore.addAgent(conversationId, agent);
|
||||||
|
|
||||||
|
const agents = get(getAgentsForConversation(conversationId));
|
||||||
|
expect(agents[0].model).toBe("claude-opus-4-6");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("leaves model undefined when not provided", () => {
|
||||||
|
const agent = createMockAgent();
|
||||||
|
agentStore.addAgent(conversationId, agent);
|
||||||
|
|
||||||
|
const agents = get(getAgentsForConversation(conversationId));
|
||||||
|
expect(agents[0].model).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
it("assigns a character name and avatar to added agents", () => {
|
it("assigns a character name and avatar to added agents", () => {
|
||||||
const agent = createMockAgent();
|
const agent = createMockAgent();
|
||||||
agentStore.addAgent(conversationId, agent);
|
agentStore.addAgent(conversationId, agent);
|
||||||
|
|||||||
@@ -515,6 +515,7 @@ export async function initializeTauriListeners() {
|
|||||||
agent_id,
|
agent_id,
|
||||||
description,
|
description,
|
||||||
subagent_type,
|
subagent_type,
|
||||||
|
model,
|
||||||
started_at,
|
started_at,
|
||||||
conversation_id,
|
conversation_id,
|
||||||
parent_tool_use_id,
|
parent_tool_use_id,
|
||||||
@@ -526,6 +527,7 @@ export async function initializeTauriListeners() {
|
|||||||
agentId: agent_id,
|
agentId: agent_id,
|
||||||
description,
|
description,
|
||||||
subagentType: subagent_type,
|
subagentType: subagent_type,
|
||||||
|
model,
|
||||||
startedAt: started_at,
|
startedAt: started_at,
|
||||||
status: "running",
|
status: "running",
|
||||||
parentToolUseId: parent_tool_use_id,
|
parentToolUseId: parent_tool_use_id,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ export interface AgentInfo {
|
|||||||
agentType?: string;
|
agentType?: string;
|
||||||
description: string;
|
description: string;
|
||||||
subagentType: string;
|
subagentType: string;
|
||||||
|
model?: string;
|
||||||
startedAt: number;
|
startedAt: number;
|
||||||
endedAt?: number;
|
endedAt?: number;
|
||||||
status: AgentStatus;
|
status: AgentStatus;
|
||||||
@@ -21,6 +22,7 @@ export interface AgentStartPayload {
|
|||||||
agent_id?: string;
|
agent_id?: string;
|
||||||
description: string;
|
description: string;
|
||||||
subagent_type: string;
|
subagent_type: string;
|
||||||
|
model?: string;
|
||||||
started_at: number;
|
started_at: number;
|
||||||
conversation_id?: string;
|
conversation_id?: string;
|
||||||
parent_tool_use_id?: string;
|
parent_tool_use_id?: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user