fix: simplify activity curator to chronological text format
Remove grouping and clever formatting. Just convert activity feed to chronological text. Changes: - Process updates in order (chronological) - Buffer message/thought chunks and flush when needed - Output tool calls and plans as they appear - No grouping, no reorganizing, no sections - Simple text format: messages, [Tool] status, [Plan] entries 🤖 Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
This commit is contained in:
co-authored by
Claude
Happy
parent
13f8e31295
commit
6106e5f65f
@@ -1,17 +1,12 @@
|
|||||||
import type { AgentUpdate } from "./types.js";
|
import type { AgentUpdate } from "./types.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Curate agent activity updates into a human-readable, token-efficient format
|
* Convert agent activity updates into chronological text format
|
||||||
* Consolidates message chunks, formats tool calls, and structures output cleanly
|
|
||||||
*/
|
*/
|
||||||
export function curateAgentActivity(updates: AgentUpdate[]): string {
|
export function curateAgentActivity(updates: AgentUpdate[]): string {
|
||||||
const sections: string[] = [];
|
const lines: string[] = [];
|
||||||
|
let messageBuffer = "";
|
||||||
// Group updates by type and consolidate
|
let thoughtBuffer = "";
|
||||||
let currentMessage = "";
|
|
||||||
let currentThought = "";
|
|
||||||
const toolCalls: Array<{ timestamp: Date; data: any }> = [];
|
|
||||||
const plans: Array<{ timestamp: Date; data: any }> = [];
|
|
||||||
|
|
||||||
for (const update of updates) {
|
for (const update of updates) {
|
||||||
const updateType = update.notification.update.sessionUpdate;
|
const updateType = update.notification.update.sessionUpdate;
|
||||||
@@ -20,121 +15,78 @@ export function curateAgentActivity(updates: AgentUpdate[]): string {
|
|||||||
switch (updateType) {
|
switch (updateType) {
|
||||||
case "agent_message_chunk":
|
case "agent_message_chunk":
|
||||||
if (content?.type === "text" && content?.text) {
|
if (content?.type === "text" && content?.text) {
|
||||||
currentMessage += content.text;
|
messageBuffer += content.text;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "agent_thought_chunk":
|
case "agent_thought_chunk":
|
||||||
if (content?.type === "text" && content?.text) {
|
if (content?.type === "text" && content?.text) {
|
||||||
currentThought += content.text;
|
thoughtBuffer += content.text;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "tool_call":
|
case "tool_call":
|
||||||
case "tool_call_update":
|
case "tool_call_update": {
|
||||||
toolCalls.push({
|
// Flush any buffered message before tool call
|
||||||
timestamp: update.timestamp,
|
if (messageBuffer.trim()) {
|
||||||
data: update.notification.update,
|
lines.push(messageBuffer.trim());
|
||||||
});
|
messageBuffer = "";
|
||||||
break;
|
}
|
||||||
|
if (thoughtBuffer.trim()) {
|
||||||
|
lines.push(`[Thought: ${thoughtBuffer.trim()}]`);
|
||||||
|
thoughtBuffer = "";
|
||||||
|
}
|
||||||
|
|
||||||
case "plan":
|
const data = update.notification.update as any;
|
||||||
plans.push({
|
const title = data.title || data.kind || "Tool";
|
||||||
timestamp: update.timestamp,
|
const status = data.status || "unknown";
|
||||||
data: (update.notification.update as any).entries,
|
|
||||||
});
|
lines.push(`\n[${title}] ${status}`);
|
||||||
|
|
||||||
|
if (data.rawInput && Object.keys(data.rawInput).length > 0) {
|
||||||
|
lines.push(`Input: ${JSON.stringify(data.rawInput)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.rawOutput && Object.keys(data.rawOutput).length > 0) {
|
||||||
|
lines.push(`Output: ${JSON.stringify(data.rawOutput)}`);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "plan": {
|
||||||
|
// Flush any buffered content before plan
|
||||||
|
if (messageBuffer.trim()) {
|
||||||
|
lines.push(messageBuffer.trim());
|
||||||
|
messageBuffer = "";
|
||||||
|
}
|
||||||
|
if (thoughtBuffer.trim()) {
|
||||||
|
lines.push(`[Thought: ${thoughtBuffer.trim()}]`);
|
||||||
|
thoughtBuffer = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const entries = (update.notification.update as any).entries;
|
||||||
|
lines.push("\n[Plan]");
|
||||||
|
for (const entry of entries) {
|
||||||
|
lines.push(`- [${entry.status}] ${entry.content}`);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "user_message_chunk":
|
||||||
|
if (content?.type === "text" && content?.text) {
|
||||||
|
lines.push(`User: ${content.text}`);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format consolidated message
|
// Flush any remaining buffered content
|
||||||
if (currentMessage.trim()) {
|
if (messageBuffer.trim()) {
|
||||||
sections.push("## Agent Response\n\n" + currentMessage.trim());
|
lines.push(messageBuffer.trim());
|
||||||
|
}
|
||||||
|
if (thoughtBuffer.trim()) {
|
||||||
|
lines.push(`[Thought: ${thoughtBuffer.trim()}]`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format consolidated thoughts
|
return lines.join("\n\n") || "No activity to display.";
|
||||||
if (currentThought.trim()) {
|
|
||||||
sections.push(
|
|
||||||
"## Agent Thoughts\n\n```\n" + currentThought.trim() + "\n```"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format tool calls
|
|
||||||
if (toolCalls.length > 0) {
|
|
||||||
const toolSection = ["## Tool Calls\n"];
|
|
||||||
|
|
||||||
// Group tool calls by toolCallId to show lifecycle
|
|
||||||
const toolGroups = new Map<string, typeof toolCalls>();
|
|
||||||
for (const call of toolCalls) {
|
|
||||||
const toolCallId = call.data.toolCallId || "unknown";
|
|
||||||
if (!toolGroups.has(toolCallId)) {
|
|
||||||
toolGroups.set(toolCallId, []);
|
|
||||||
}
|
|
||||||
toolGroups.get(toolCallId)!.push(call);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const [toolCallId, calls] of toolGroups) {
|
|
||||||
const latestCall = calls[calls.length - 1];
|
|
||||||
const data = latestCall.data;
|
|
||||||
|
|
||||||
toolSection.push(`\n### ${data.title || data.kind || "Tool"}`);
|
|
||||||
toolSection.push(`- **Status**: ${data.status || "unknown"}`);
|
|
||||||
toolSection.push(`- **Call ID**: ${toolCallId.slice(0, 8)}...`);
|
|
||||||
|
|
||||||
if (data.rawInput && Object.keys(data.rawInput).length > 0) {
|
|
||||||
toolSection.push(`- **Input**: ${JSON.stringify(data.rawInput, null, 2)}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.rawOutput && Object.keys(data.rawOutput).length > 0) {
|
|
||||||
toolSection.push(`- **Output**: ${JSON.stringify(data.rawOutput, null, 2)}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.content && data.content.length > 0) {
|
|
||||||
toolSection.push(`- **Content**: ${formatToolContent(data.content)}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sections.push(toolSection.join("\n"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format plans
|
|
||||||
if (plans.length > 0) {
|
|
||||||
const latestPlan = plans[plans.length - 1];
|
|
||||||
const planSection = ["## Plan\n"];
|
|
||||||
|
|
||||||
for (const entry of latestPlan.data) {
|
|
||||||
const icon =
|
|
||||||
entry.status === "completed" ? "✅" :
|
|
||||||
entry.status === "in_progress" ? "🔄" :
|
|
||||||
"⏳";
|
|
||||||
|
|
||||||
const priority =
|
|
||||||
entry.priority === "high" ? "🔴" :
|
|
||||||
entry.priority === "medium" ? "🟡" :
|
|
||||||
"🟢";
|
|
||||||
|
|
||||||
planSection.push(`${icon} ${priority} ${entry.content}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
sections.push(planSection.join("\n"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return sections.join("\n\n---\n\n") || "No activity to display.";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Format tool call content into readable text
|
|
||||||
*/
|
|
||||||
function formatToolContent(content: any[]): string {
|
|
||||||
return content
|
|
||||||
.map((item) => {
|
|
||||||
if (item.type === "text") {
|
|
||||||
return item.text;
|
|
||||||
}
|
|
||||||
if (item.type === "image") {
|
|
||||||
return `[Image: ${item.source || "embedded"}]`;
|
|
||||||
}
|
|
||||||
return JSON.stringify(item);
|
|
||||||
})
|
|
||||||
.join("\n");
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user