mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-06 16:34:36 +00:00
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.
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