perf: remove raw field from timeline items to reduce payload size
Remove the `raw` field that was duplicating provider data in timeline items, reducing WebSocket payload sizes by 64-85%: - session_state: ~320KB → ~48KB - agent_stream_snapshot: ~320KB → ~114KB Changes: - Remove raw from AgentTimelineItem, AgentStreamEvent, AgentPermissionRequest - Remove raw assignments from claude-agent.ts and codex-agent.ts - Remove provider_event handling from stream.ts (only used for Codex raw) - Update tests to reflect new behavior 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -352,14 +352,13 @@ export class AgentManager {
|
||||
recordUserMessage(
|
||||
agentId: string,
|
||||
text: string,
|
||||
options?: { messageId?: string; raw?: unknown }
|
||||
options?: { messageId?: string }
|
||||
): void {
|
||||
const agent = this.requireAgent(agentId);
|
||||
const item: AgentTimelineItem = {
|
||||
type: "user_message",
|
||||
text,
|
||||
messageId: options?.messageId,
|
||||
raw: options?.raw,
|
||||
};
|
||||
agent.updatedAt = new Date();
|
||||
agent.lastUserMessageAt = agent.updatedAt;
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import type { ThreadEvent as CodexThreadEvent } from "@openai/codex-sdk";
|
||||
import type {
|
||||
Options as ClaudeAgentOptions,
|
||||
SDKMessage as ClaudeStreamMessage,
|
||||
} from "@anthropic-ai/claude-agent-sdk";
|
||||
import type { Options as ClaudeAgentOptions } from "@anthropic-ai/claude-agent-sdk";
|
||||
|
||||
export type AgentProvider = "codex" | "claude";
|
||||
|
||||
@@ -54,9 +50,9 @@ export type AgentUsage = {
|
||||
};
|
||||
|
||||
export type AgentTimelineItem =
|
||||
| { type: "user_message"; text: string; messageId?: string; raw?: unknown }
|
||||
| { type: "assistant_message"; text: string; raw?: unknown }
|
||||
| { type: "reasoning"; text: string; raw?: unknown }
|
||||
| { type: "user_message"; text: string; messageId?: string }
|
||||
| { type: "assistant_message"; text: string }
|
||||
| { type: "reasoning"; text: string }
|
||||
| {
|
||||
type: "tool_call";
|
||||
server: string;
|
||||
@@ -68,10 +64,9 @@ export type AgentTimelineItem =
|
||||
input?: unknown;
|
||||
output?: unknown;
|
||||
error?: unknown;
|
||||
raw?: unknown;
|
||||
}
|
||||
| { type: "todo"; items: { text: string; completed: boolean }[]; raw?: unknown }
|
||||
| { type: "error"; message: string; raw?: unknown };
|
||||
| { type: "todo"; items: { text: string; completed: boolean }[] }
|
||||
| { type: "error"; message: string };
|
||||
|
||||
export type AgentStreamEvent =
|
||||
| { type: "thread_started"; sessionId: string; provider: AgentProvider }
|
||||
@@ -79,7 +74,6 @@ export type AgentStreamEvent =
|
||||
| { type: "turn_completed"; provider: AgentProvider; usage?: AgentUsage }
|
||||
| { type: "turn_failed"; provider: AgentProvider; error: string }
|
||||
| { type: "timeline"; item: AgentTimelineItem; provider: AgentProvider }
|
||||
| { type: "provider_event"; provider: AgentProvider; raw: CodexThreadEvent | ClaudeStreamMessage }
|
||||
| { type: "permission_requested"; provider: AgentProvider; request: AgentPermissionRequest }
|
||||
| {
|
||||
type: "permission_resolved";
|
||||
@@ -102,7 +96,6 @@ export type AgentPermissionRequest = {
|
||||
input?: Record<string, unknown>;
|
||||
suggestions?: AgentPermissionUpdate[];
|
||||
metadata?: Record<string, unknown>;
|
||||
raw?: unknown;
|
||||
};
|
||||
|
||||
export type AgentPermissionResponse =
|
||||
|
||||
@@ -405,7 +405,6 @@ class ClaudeAgentSession implements AgentSession {
|
||||
callId: pending.request.id,
|
||||
displayName: "Plan approved",
|
||||
kind: "plan",
|
||||
raw: pending.request,
|
||||
});
|
||||
}
|
||||
const result: PermissionResult = {
|
||||
@@ -422,7 +421,6 @@ class ClaudeAgentSession implements AgentSession {
|
||||
displayName: pending.request.title ?? pending.request.name,
|
||||
kind: "permission",
|
||||
input: pending.request.input,
|
||||
raw: { request: pending.request, response },
|
||||
});
|
||||
} else {
|
||||
const result: PermissionResult = {
|
||||
@@ -439,7 +437,6 @@ class ClaudeAgentSession implements AgentSession {
|
||||
displayName: pending.request.title ?? pending.request.name,
|
||||
kind: "permission",
|
||||
input: pending.request.input,
|
||||
raw: { request: pending.request, response },
|
||||
});
|
||||
}
|
||||
|
||||
@@ -618,7 +615,7 @@ class ClaudeAgentSession implements AgentSession {
|
||||
}
|
||||
|
||||
private translateMessageToEvents(message: SDKMessage): AgentStreamEvent[] {
|
||||
const events: AgentStreamEvent[] = [{ type: "provider_event", provider: "claude", raw: message }];
|
||||
const events: AgentStreamEvent[] = [];
|
||||
|
||||
switch (message.type) {
|
||||
case "system":
|
||||
@@ -722,7 +719,6 @@ class ClaudeAgentSession implements AgentSession {
|
||||
input,
|
||||
suggestions: options?.suggestions as AgentPermissionUpdate[] | undefined,
|
||||
metadata: Object.keys(metadata).length ? metadata : undefined,
|
||||
raw: { toolName, input, options },
|
||||
};
|
||||
|
||||
this.pushToolCall({
|
||||
@@ -733,7 +729,6 @@ class ClaudeAgentSession implements AgentSession {
|
||||
displayName: request.title ?? toolName,
|
||||
kind: "permission",
|
||||
input,
|
||||
raw: { toolName, input },
|
||||
});
|
||||
|
||||
this.pushEvent({ type: "permission_requested", provider: "claude", request });
|
||||
@@ -762,7 +757,6 @@ class ClaudeAgentSession implements AgentSession {
|
||||
displayName: request.title ?? toolName,
|
||||
kind: "permission",
|
||||
input,
|
||||
raw: { reason: "timeout", toolName, input },
|
||||
});
|
||||
this.pushEvent({
|
||||
type: "permission_resolved",
|
||||
@@ -808,7 +802,6 @@ class ClaudeAgentSession implements AgentSession {
|
||||
this.enqueueTimeline({
|
||||
type: "todo",
|
||||
items: todoItems.length > 0 ? todoItems : [{ text: planText, completed: false }],
|
||||
raw: input,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -939,7 +932,7 @@ class ClaudeAgentSession implements AgentSession {
|
||||
if (suppressAssistant) {
|
||||
return [];
|
||||
}
|
||||
return [{ type: "assistant_message", text: content, raw: content }];
|
||||
return [{ type: "assistant_message", text: content }];
|
||||
}
|
||||
|
||||
const items: AgentTimelineItem[] = [];
|
||||
@@ -952,7 +945,7 @@ class ClaudeAgentSession implements AgentSession {
|
||||
this.streamedAssistantTextThisTurn = true;
|
||||
}
|
||||
if (!suppressAssistant) {
|
||||
items.push({ type: "assistant_message", text: block.text, raw: block });
|
||||
items.push({ type: "assistant_message", text: block.text });
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -963,7 +956,7 @@ class ClaudeAgentSession implements AgentSession {
|
||||
this.streamedReasoningThisTurn = true;
|
||||
}
|
||||
if (!suppressReasoning) {
|
||||
items.push({ type: "reasoning", text: block.thinking, raw: block });
|
||||
items.push({ type: "reasoning", text: block.thinking });
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1009,7 +1002,6 @@ class ClaudeAgentSession implements AgentSession {
|
||||
displayName: this.buildToolDisplayName(entry),
|
||||
kind: this.getToolKind(entry.classification),
|
||||
input: entry.input ?? this.normalizeToolInput(block.input),
|
||||
raw: block,
|
||||
},
|
||||
items
|
||||
);
|
||||
@@ -1020,10 +1012,6 @@ class ClaudeAgentSession implements AgentSession {
|
||||
const server = entry?.server ?? block.server ?? "tool";
|
||||
const tool = entry?.name ?? block.tool_name ?? "tool";
|
||||
const status = block.is_error ? "failed" : "completed";
|
||||
const rawPayload =
|
||||
!block.is_error && entry?.classification === "file_change" && entry.files?.length
|
||||
? { block, files: entry.files }
|
||||
: block;
|
||||
this.pushToolCall(
|
||||
{
|
||||
server,
|
||||
@@ -1035,7 +1023,6 @@ class ClaudeAgentSession implements AgentSession {
|
||||
input: entry?.input,
|
||||
output: !block.is_error && entry?.files?.length ? { files: entry.files } : undefined,
|
||||
error: block.is_error ? block : undefined,
|
||||
raw: rawPayload,
|
||||
},
|
||||
items
|
||||
);
|
||||
@@ -1143,7 +1130,6 @@ class ClaudeAgentSession implements AgentSession {
|
||||
displayName: this.buildToolDisplayName(entry),
|
||||
kind: this.getToolKind(entry.classification),
|
||||
input: normalized,
|
||||
raw: { type: "tool_use", id: toolId, input: parsed },
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1312,7 +1298,6 @@ export function convertClaudeHistoryEntry(
|
||||
timeline.push({
|
||||
type: "user_message",
|
||||
text,
|
||||
raw: message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -446,7 +446,6 @@ class CodexAgentSession implements AgentSession {
|
||||
displayName: request.title ?? request.name,
|
||||
kind: "permission",
|
||||
input: request.input,
|
||||
raw: { request, response },
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -610,7 +609,6 @@ class CodexAgentSession implements AgentSession {
|
||||
}
|
||||
|
||||
private *translateEvent(event: ThreadEvent): Generator<AgentStreamEvent> {
|
||||
yield { type: "provider_event", provider: "codex", raw: event };
|
||||
|
||||
const permissionEvents = this.handlePermissionEvent(event);
|
||||
if (permissionEvents) {
|
||||
@@ -658,7 +656,7 @@ class CodexAgentSession implements AgentSession {
|
||||
yield {
|
||||
type: "timeline",
|
||||
provider: "codex",
|
||||
item: { type: "error", message, raw: event },
|
||||
item: { type: "error", message },
|
||||
};
|
||||
yield { type: "turn_failed", provider: "codex", error: message };
|
||||
break;
|
||||
@@ -706,7 +704,6 @@ class CodexAgentSession implements AgentSession {
|
||||
displayName: request.title ?? request.name,
|
||||
kind: "permission",
|
||||
input: request.input,
|
||||
raw: request.raw,
|
||||
}),
|
||||
},
|
||||
{ type: "permission_requested", provider: "codex", request },
|
||||
@@ -763,7 +760,6 @@ class CodexAgentSession implements AgentSession {
|
||||
parsedCommand,
|
||||
},
|
||||
metadata: sanitizeMetadata(metadata),
|
||||
raw,
|
||||
};
|
||||
|
||||
return request;
|
||||
@@ -810,7 +806,6 @@ class CodexAgentSession implements AgentSession {
|
||||
input,
|
||||
suggestions: grantRoot ? [{ grantRoot }] : undefined,
|
||||
metadata: sanitizeMetadata(metadata),
|
||||
raw,
|
||||
};
|
||||
|
||||
return request;
|
||||
@@ -819,9 +814,9 @@ class CodexAgentSession implements AgentSession {
|
||||
private threadItemToTimeline(item: ThreadItem): AgentTimelineItem | null {
|
||||
switch (item.type) {
|
||||
case "agent_message":
|
||||
return { type: "assistant_message", text: item.text, raw: item };
|
||||
return { type: "assistant_message", text: item.text };
|
||||
case "reasoning":
|
||||
return { type: "reasoning", text: item.text, raw: item };
|
||||
return { type: "reasoning", text: item.text };
|
||||
case "command_execution":
|
||||
return createToolCallTimelineItem({
|
||||
server: "command",
|
||||
@@ -833,7 +828,6 @@ class CodexAgentSession implements AgentSession {
|
||||
input: { command: item.command, cwd: (item as any)?.cwd },
|
||||
output: (item as any)?.output,
|
||||
error: (item as any)?.error,
|
||||
raw: item,
|
||||
});
|
||||
case "file_change": {
|
||||
const files = item.changes.map((change) => ({ path: change.path, kind: change.kind }));
|
||||
@@ -845,7 +839,6 @@ class CodexAgentSession implements AgentSession {
|
||||
displayName: buildFileChangeSummary(files),
|
||||
kind: "edit",
|
||||
output: { files },
|
||||
raw: item,
|
||||
});
|
||||
}
|
||||
case "mcp_tool_call":
|
||||
@@ -858,7 +851,6 @@ class CodexAgentSession implements AgentSession {
|
||||
kind: "tool",
|
||||
input: (item as any)?.input,
|
||||
output: (item as any)?.output,
|
||||
raw: item,
|
||||
});
|
||||
case "web_search":
|
||||
return createToolCallTimelineItem({
|
||||
@@ -869,12 +861,11 @@ class CodexAgentSession implements AgentSession {
|
||||
displayName: item.query ? `Web search: ${item.query}` : "Web search",
|
||||
kind: "search",
|
||||
input: { query: item.query },
|
||||
raw: item,
|
||||
});
|
||||
case "todo_list":
|
||||
return { type: "todo", items: item.items, raw: item };
|
||||
return { type: "todo", items: item.items };
|
||||
case "error":
|
||||
return { type: "error", message: item.message, raw: item };
|
||||
return { type: "error", message: item.message };
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@@ -992,12 +983,12 @@ function handleRolloutResponseItem(
|
||||
const text = extractMessageText(payload.content);
|
||||
if (text) {
|
||||
if (payload.role === "assistant") {
|
||||
events.push({ type: "timeline", provider: "codex", item: { type: "assistant_message", text, raw: payload } });
|
||||
events.push({ type: "timeline", provider: "codex", item: { type: "assistant_message", text } });
|
||||
} else if (payload.role === "user") {
|
||||
if (isSyntheticRolloutUserMessage(text)) {
|
||||
break;
|
||||
}
|
||||
events.push({ type: "timeline", provider: "codex", item: { type: "user_message", text, raw: payload } });
|
||||
events.push({ type: "timeline", provider: "codex", item: { type: "user_message", text } });
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1005,7 +996,7 @@ function handleRolloutResponseItem(
|
||||
case "reasoning": {
|
||||
const text = extractReasoningText(payload);
|
||||
if (text) {
|
||||
events.push({ type: "timeline", provider: "codex", item: { type: "reasoning", text, raw: payload } });
|
||||
events.push({ type: "timeline", provider: "codex", item: { type: "reasoning", text } });
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1031,7 +1022,7 @@ function handleRolloutEventMessage(payload: RolloutEventPayload | undefined, eve
|
||||
return;
|
||||
}
|
||||
if (payload.type === "agent_reasoning" && typeof payload.text === "string") {
|
||||
events.push({ type: "timeline", provider: "codex", item: { type: "reasoning", text: payload.text, raw: payload } });
|
||||
events.push({ type: "timeline", provider: "codex", item: { type: "reasoning", text: payload.text } });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1064,7 +1055,6 @@ function handleRolloutFunctionCall(
|
||||
displayName: buildCommandDisplayName(command),
|
||||
kind: "execute",
|
||||
input: { command, cwd },
|
||||
raw: payload,
|
||||
}),
|
||||
});
|
||||
}
|
||||
@@ -1075,7 +1065,7 @@ function handleRolloutFunctionCall(
|
||||
const args = safeJsonParse<{ plan?: unknown }>(payload.arguments);
|
||||
const planItems = parsePlanItems(args);
|
||||
if (planItems.length) {
|
||||
events.push({ type: "timeline", provider: "codex", item: { type: "todo", items: planItems, raw: payload } });
|
||||
events.push({ type: "timeline", provider: "codex", item: { type: "todo", items: planItems } });
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1091,7 +1081,6 @@ function handleRolloutFunctionCall(
|
||||
displayName: `${name}`,
|
||||
kind: "tool",
|
||||
input: safeJsonParse(payload.arguments),
|
||||
raw: payload,
|
||||
}),
|
||||
});
|
||||
}
|
||||
@@ -1123,7 +1112,6 @@ function finalizeRolloutFunctionCall(
|
||||
kind: "execute",
|
||||
input: { command: command.command, cwd: command.cwd },
|
||||
output: result,
|
||||
raw: { payload, result },
|
||||
}),
|
||||
});
|
||||
commandCalls.delete(payload.call_id);
|
||||
@@ -1143,7 +1131,6 @@ function handleRolloutCustomToolCall(payload: RolloutCustomToolCallPayload, even
|
||||
displayName: buildFileChangeSummary(files),
|
||||
kind: "edit",
|
||||
output: { files },
|
||||
raw: payload,
|
||||
}),
|
||||
});
|
||||
}
|
||||
@@ -1162,7 +1149,6 @@ function handleRolloutCustomToolCall(payload: RolloutCustomToolCallPayload, even
|
||||
kind: "tool",
|
||||
input: payload.input,
|
||||
output: payload.output,
|
||||
raw: payload,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -13,11 +13,6 @@ import type {
|
||||
AgentUsage,
|
||||
} from "./agent/agent-sdk-types.js";
|
||||
|
||||
type ProviderEventPayload = Extract<
|
||||
AgentStreamEvent,
|
||||
{ type: "provider_event" }
|
||||
>;
|
||||
|
||||
export type AgentSnapshotPayload = Omit<
|
||||
AgentSnapshot,
|
||||
"createdAt" | "updatedAt" | "lastUserMessageAt"
|
||||
@@ -118,7 +113,6 @@ export const AgentPermissionRequestPayloadSchema: z.ZodType<AgentPermissionReque
|
||||
input: z.record(z.unknown()).optional(),
|
||||
suggestions: z.array(AgentPermissionUpdateSchema).optional(),
|
||||
metadata: z.record(z.unknown()).optional(),
|
||||
raw: z.unknown().optional(),
|
||||
});
|
||||
|
||||
export const AgentTimelineItemPayloadSchema: z.ZodType<AgentTimelineItem> =
|
||||
@@ -127,17 +121,14 @@ export const AgentTimelineItemPayloadSchema: z.ZodType<AgentTimelineItem> =
|
||||
type: z.literal("user_message"),
|
||||
text: z.string(),
|
||||
messageId: z.string().optional(),
|
||||
raw: z.unknown().optional(),
|
||||
}),
|
||||
z.object({
|
||||
type: z.literal("assistant_message"),
|
||||
text: z.string(),
|
||||
raw: z.unknown().optional(),
|
||||
}),
|
||||
z.object({
|
||||
type: z.literal("reasoning"),
|
||||
text: z.string(),
|
||||
raw: z.unknown().optional(),
|
||||
}),
|
||||
z.object({
|
||||
type: z.literal("tool_call"),
|
||||
@@ -150,7 +141,6 @@ export const AgentTimelineItemPayloadSchema: z.ZodType<AgentTimelineItem> =
|
||||
input: z.unknown().optional(),
|
||||
output: z.unknown().optional(),
|
||||
error: z.unknown().optional(),
|
||||
raw: z.unknown().optional(),
|
||||
}),
|
||||
z.object({
|
||||
type: z.literal("todo"),
|
||||
@@ -160,21 +150,13 @@ export const AgentTimelineItemPayloadSchema: z.ZodType<AgentTimelineItem> =
|
||||
completed: z.boolean(),
|
||||
})
|
||||
),
|
||||
raw: z.unknown().optional(),
|
||||
}),
|
||||
z.object({
|
||||
type: z.literal("error"),
|
||||
message: z.string(),
|
||||
raw: z.unknown().optional(),
|
||||
}),
|
||||
]);
|
||||
|
||||
const ProviderEventPayloadSchema = z.object({
|
||||
type: z.literal("provider_event"),
|
||||
provider: AgentProviderSchema,
|
||||
raw: z.custom<ProviderEventPayload["raw"]>(),
|
||||
});
|
||||
|
||||
export const AgentStreamEventPayloadSchema = z.discriminatedUnion("type", [
|
||||
z.object({
|
||||
type: z.literal("thread_started"),
|
||||
@@ -200,7 +182,6 @@ export const AgentStreamEventPayloadSchema = z.discriminatedUnion("type", [
|
||||
provider: AgentProviderSchema,
|
||||
item: AgentTimelineItemPayloadSchema,
|
||||
}),
|
||||
ProviderEventPayloadSchema,
|
||||
z.object({
|
||||
type: z.literal("permission_requested"),
|
||||
provider: AgentProviderSchema,
|
||||
|
||||
@@ -2029,10 +2029,7 @@ export class Session {
|
||||
|
||||
this.emit({
|
||||
type: "agent_stream_snapshot",
|
||||
payload: {
|
||||
agentId: agent.id,
|
||||
events,
|
||||
},
|
||||
payload: { agentId: agent.id, events },
|
||||
});
|
||||
|
||||
return timeline.length;
|
||||
|
||||
Reference in New Issue
Block a user