mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
Reduce workspace, agent, and chat sync traffic (#2028)
* feat(sync): keep live data scoped and current Only viewed chats receive live timeline rows, while directory state now uses one subscribed bootstrap followed by ordered deltas. Legacy clients and daemons retain their existing behavior through centralized compatibility gates. * fix(sync): preserve selective delivery boundaries Keep selective timeline capability app-owned, union viewed sets across shared sockets, and reconcile directory side effects from accepted state. Visibility and archive suppression now follow their existing authoritative boundaries. * test(app): align browser fixtures with runtime contracts * fix(sync): preserve mixed-client delivery guarantees * fix(sync): finish paged history before advancing * fix(sync): replay live deltas after refresh failures * test(server): model socket capability lookup * test(app): use platform shortcut for split-pane coverage * fix(app): keep hidden timelines dormant * test(app): normalize split-pane shortcut setup * fix(app): preserve sync state across retries * fix(app): preserve background sync state across races * fix directory bootstrap reconciliation edge cases * fix selective timeline compatibility races * fix superseded directory sync races * fix(sync): centralize directory replica ordering Own agent and workspace refresh transactions in HostRuntime so reconnect epochs, buffered updates, and lifecycle invalidation share one ordering boundary. Route timeline metadata and mixed-capability stream delivery through their authoritative runtime sources. * fix(app): keep timeline requests runtime-scoped * fix(app): close directory bootstrap races
This commit is contained in:
@@ -1,4 +1,8 @@
|
||||
export const CLIENT_CAPS = {
|
||||
// COMPAT(selectiveAgentTimeline): added in v0.1.106. Capable clients receive
|
||||
// agent streams only for their explicit viewed set. Remove after 2027-01-12
|
||||
// once the supported client floor is >= v0.1.106.
|
||||
selectiveAgentTimeline: "selective_agent_timeline",
|
||||
reasoningMergeEnum: "reasoning_merge_enum",
|
||||
// COMPAT(customModeIcons): added in v0.1.84. Old clients pin AgentModeIcon to
|
||||
// a closed enum and crash rendering unknown values; daemon downgrades icons
|
||||
|
||||
@@ -437,3 +437,35 @@ describe("daemon update messages", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("viewed timeline subscription messages", () => {
|
||||
test("parses a complete viewed-agent set and its acknowledgement", () => {
|
||||
const request = SessionInboundMessageSchema.parse({
|
||||
type: "agent.timeline.set_subscription.request",
|
||||
agentIds: ["agent-a", "agent-b"],
|
||||
requestId: "timeline-subscription-1",
|
||||
});
|
||||
const response = SessionOutboundMessageSchema.parse({
|
||||
type: "agent.timeline.set_subscription.response",
|
||||
payload: {
|
||||
agentIds: ["agent-a", "agent-b"],
|
||||
requestId: "timeline-subscription-1",
|
||||
},
|
||||
});
|
||||
|
||||
expect({ request, response }).toEqual({
|
||||
request: {
|
||||
type: "agent.timeline.set_subscription.request",
|
||||
agentIds: ["agent-a", "agent-b"],
|
||||
requestId: "timeline-subscription-1",
|
||||
},
|
||||
response: {
|
||||
type: "agent.timeline.set_subscription.response",
|
||||
payload: {
|
||||
agentIds: ["agent-a", "agent-b"],
|
||||
requestId: "timeline-subscription-1",
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1369,6 +1369,12 @@ export const ProviderSubagentTimelineRequestMessageSchema = z.object({
|
||||
limit: z.number().int().nonnegative().optional(),
|
||||
});
|
||||
|
||||
export const SetAgentTimelineSubscriptionRequestMessageSchema = z.object({
|
||||
type: z.literal("agent.timeline.set_subscription.request"),
|
||||
agentIds: z.array(z.string()),
|
||||
requestId: z.string(),
|
||||
});
|
||||
|
||||
export const AgentForkContextRequestMessageSchema = z.object({
|
||||
type: z.literal("agent.fork_context.request"),
|
||||
agentId: z.string(),
|
||||
@@ -2359,6 +2365,7 @@ export const SessionInboundMessageSchema = z.discriminatedUnion("type", [
|
||||
FetchAgentTimelineRequestMessageSchema,
|
||||
ProviderSubagentListRequestMessageSchema,
|
||||
ProviderSubagentTimelineRequestMessageSchema,
|
||||
SetAgentTimelineSubscriptionRequestMessageSchema,
|
||||
AgentForkContextRequestMessageSchema,
|
||||
SetAgentModeRequestMessageSchema,
|
||||
SetAgentModelRequestMessageSchema,
|
||||
@@ -2678,6 +2685,8 @@ export const ServerInfoStatusPayloadSchema = z
|
||||
// Daemon advertises pluggable non-GitHub forge support (the forge registry);
|
||||
// the client gates non-GitHub setup UI on it.
|
||||
forgeProviders: z.boolean().optional(),
|
||||
// COMPAT(selectiveAgentTimeline): added in v0.1.106, remove after 2027-01-12.
|
||||
selectiveAgentTimeline: z.boolean().optional(),
|
||||
})
|
||||
.optional(),
|
||||
})
|
||||
@@ -3425,6 +3434,35 @@ export const ProviderSubagentUpdateMessageSchema = z.object({
|
||||
]),
|
||||
});
|
||||
|
||||
export const SetAgentTimelineSubscriptionResponseMessageSchema = z.object({
|
||||
type: z.literal("agent.timeline.set_subscription.response"),
|
||||
payload: z.object({
|
||||
agentIds: z.array(z.string()),
|
||||
requestId: z.string(),
|
||||
}),
|
||||
});
|
||||
|
||||
export const AgentAttentionRequiredMessageSchema = z.object({
|
||||
type: z.literal("agent_attention_required"),
|
||||
payload: z.object({
|
||||
agentId: z.string(),
|
||||
reason: z.enum(["finished", "error", "permission"]),
|
||||
timestamp: z.string(),
|
||||
shouldNotify: z.boolean(),
|
||||
notification: z
|
||||
.object({
|
||||
title: z.string(),
|
||||
body: z.string(),
|
||||
data: z.object({
|
||||
serverId: z.string(),
|
||||
agentId: z.string(),
|
||||
reason: z.enum(["finished", "error", "permission"]),
|
||||
}),
|
||||
})
|
||||
.optional(),
|
||||
}),
|
||||
});
|
||||
|
||||
export const AgentForkContextResponseMessageSchema = z.object({
|
||||
type: z.literal("agent.fork_context.response"),
|
||||
payload: z.object({
|
||||
@@ -4832,6 +4870,8 @@ export const SessionOutboundMessageSchema = z.discriminatedUnion("type", [
|
||||
ProviderSubagentListResponseMessageSchema,
|
||||
ProviderSubagentTimelineResponseMessageSchema,
|
||||
ProviderSubagentUpdateMessageSchema,
|
||||
SetAgentTimelineSubscriptionResponseMessageSchema,
|
||||
AgentAttentionRequiredMessageSchema,
|
||||
AgentForkContextResponseMessageSchema,
|
||||
CancelAgentResponseMessageSchema,
|
||||
ClearAgentAttentionResponseMessageSchema,
|
||||
@@ -5365,6 +5405,7 @@ export const WSHelloMessageSchema = z.object({
|
||||
voice: z.boolean().optional(),
|
||||
pushNotifications: z.boolean().optional(),
|
||||
[CLIENT_CAPS.reasoningMergeEnum]: z.boolean().optional(),
|
||||
[CLIENT_CAPS.selectiveAgentTimeline]: z.boolean().optional(),
|
||||
[CLIENT_CAPS.customModeIcons]: z.boolean().optional(),
|
||||
[CLIENT_CAPS.terminalReflowableSnapshot]: z.boolean().optional(),
|
||||
[CLIENT_CAPS.providerSubagents]: z.boolean().optional(),
|
||||
|
||||
Reference in New Issue
Block a user