Show provider subagents in the subagents track (#2013)
* Add provider-owned subagent stream contract * OpenCode provider: detect child sessions, attach adopted children to the hosting server, synthesize external turns - Emit internal provider_child_session_detected / provider_session_deleted stream events from the global event stream (before the no-active-turn gate), including BFS hydration of existing descendants on subscribe - Track child sessions in a registry mapping child session id -> hosting server url; resumeSession attaches via acquireExisting() so adopted children share the parent's server generation and keep receiving live events - Synthesize external turns for adopted (externally driven) sessions so timeline, tool calls, and permission requests stream without a Paseo-initiated prompt - Honor launchContext.env in resumeSession (acquireDedicated parity with createSession) - Stop folding child tool parts into the parent's sub_agent action log; the parent row stays as a pointer * Render provider subagents in workspace timelines * fix provider subagent timeline reliability * fix provider subagent lifecycle edge cases * fix provider subagent event fidelity * Fix provider subagent history fidelity * Fix restored provider subagent state * Fix provider subagent visibility edges * Restore provider subagent timelines * Page provider subagent history * Forward subagent questions reliably * fix(subagents): preserve OpenCode child context * fix(subagents): harden provider timeline routing * fix(subagents): preserve provider page continuity * fix(subagents): retain live child prompts --------- Co-authored-by: Omer <639682+omercnet@users.noreply.github.com>
This commit is contained in:
@@ -1295,6 +1295,22 @@ export const FetchAgentTimelineRequestMessageSchema = z.object({
|
||||
projection: z.enum(["projected", "canonical"]).optional(),
|
||||
});
|
||||
|
||||
export const ProviderSubagentListRequestMessageSchema = z.object({
|
||||
type: z.literal("agent.provider_subagents.list.request"),
|
||||
parentAgentId: z.string(),
|
||||
requestId: z.string(),
|
||||
});
|
||||
|
||||
export const ProviderSubagentTimelineRequestMessageSchema = z.object({
|
||||
type: z.literal("agent.provider_subagents.timeline.get.request"),
|
||||
parentAgentId: z.string(),
|
||||
subagentId: z.string(),
|
||||
requestId: z.string(),
|
||||
direction: z.enum(["tail", "before", "after"]).optional(),
|
||||
cursor: AgentTimelineCursorSchema.optional(),
|
||||
limit: z.number().int().nonnegative().optional(),
|
||||
});
|
||||
|
||||
export const AgentForkContextRequestMessageSchema = z.object({
|
||||
type: z.literal("agent.fork_context.request"),
|
||||
agentId: z.string(),
|
||||
@@ -2089,6 +2105,8 @@ export const SessionInboundMessageSchema = z.discriminatedUnion("type", [
|
||||
RestartServerRequestMessageSchema,
|
||||
DaemonUpdateRequestMessageSchema,
|
||||
FetchAgentTimelineRequestMessageSchema,
|
||||
ProviderSubagentListRequestMessageSchema,
|
||||
ProviderSubagentTimelineRequestMessageSchema,
|
||||
AgentForkContextRequestMessageSchema,
|
||||
SetAgentModeRequestMessageSchema,
|
||||
SetAgentModelRequestMessageSchema,
|
||||
@@ -2367,6 +2385,8 @@ export const ServerInfoStatusPayloadSchema = z
|
||||
daemonSelfUpdate: z.boolean().optional(),
|
||||
// COMPAT(agentForkContext): added in v0.1.102, remove gate after 2026-12-28.
|
||||
agentForkContext: z.boolean().optional(),
|
||||
// COMPAT(providerSubagents): added in v0.1.107, remove gate after 2027-01-12.
|
||||
providerSubagents: z.boolean().optional(),
|
||||
})
|
||||
.optional(),
|
||||
})
|
||||
@@ -2958,6 +2978,88 @@ export const FetchAgentTimelineResponseMessageSchema = z.object({
|
||||
}),
|
||||
});
|
||||
|
||||
export const ProviderSubagentDescriptorPayloadSchema = z.object({
|
||||
id: z.string(),
|
||||
parentAgentId: z.string(),
|
||||
provider: AgentProviderSchema,
|
||||
title: z.string().nullable(),
|
||||
description: z.string().nullable(),
|
||||
status: z.enum(["running", "completed", "failed", "canceled"]),
|
||||
createdAt: z.string(),
|
||||
updatedAt: z.string(),
|
||||
toolCallId: z.string().nullable(),
|
||||
cwd: z.string().nullable().optional(),
|
||||
});
|
||||
|
||||
export type ProviderSubagentDescriptorPayload = z.infer<
|
||||
typeof ProviderSubagentDescriptorPayloadSchema
|
||||
>;
|
||||
|
||||
export const ProviderSubagentListResponseMessageSchema = z.object({
|
||||
type: z.literal("agent.provider_subagents.list.response"),
|
||||
payload: z.object({
|
||||
requestId: z.string(),
|
||||
parentAgentId: z.string(),
|
||||
subagents: z.array(ProviderSubagentDescriptorPayloadSchema),
|
||||
error: z.string().nullable(),
|
||||
}),
|
||||
});
|
||||
|
||||
export const ProviderSubagentTimelineResponseMessageSchema = z.object({
|
||||
type: z.literal("agent.provider_subagents.timeline.get.response"),
|
||||
payload: z.object({
|
||||
requestId: z.string(),
|
||||
parentAgentId: z.string(),
|
||||
subagentId: z.string(),
|
||||
provider: AgentProviderSchema.nullable(),
|
||||
direction: z.enum(["tail", "before", "after"]),
|
||||
epoch: z.string(),
|
||||
reset: z.boolean(),
|
||||
staleCursor: z.boolean(),
|
||||
gap: z.boolean(),
|
||||
window: z.object({
|
||||
minSeq: z.number().int().nonnegative(),
|
||||
maxSeq: z.number().int().nonnegative(),
|
||||
nextSeq: z.number().int().nonnegative(),
|
||||
}),
|
||||
hasOlder: z.boolean(),
|
||||
hasNewer: z.boolean(),
|
||||
rows: z.array(
|
||||
z.object({
|
||||
item: AgentTimelineItemPayloadSchema,
|
||||
timestamp: z.string(),
|
||||
seq: z.number().int().nonnegative(),
|
||||
}),
|
||||
),
|
||||
error: z.string().nullable(),
|
||||
}),
|
||||
});
|
||||
|
||||
export const ProviderSubagentUpdateMessageSchema = z.object({
|
||||
type: z.literal("agent.provider_subagents.update"),
|
||||
payload: z.discriminatedUnion("kind", [
|
||||
z.object({
|
||||
kind: z.literal("upsert"),
|
||||
subagent: ProviderSubagentDescriptorPayloadSchema,
|
||||
}),
|
||||
z.object({
|
||||
kind: z.literal("timeline"),
|
||||
parentAgentId: z.string(),
|
||||
subagentId: z.string(),
|
||||
provider: AgentProviderSchema,
|
||||
item: AgentTimelineItemPayloadSchema,
|
||||
timestamp: z.string(),
|
||||
seq: z.number().int().nonnegative(),
|
||||
epoch: z.string(),
|
||||
}),
|
||||
z.object({
|
||||
kind: z.literal("remove"),
|
||||
parentAgentId: z.string(),
|
||||
subagentId: z.string(),
|
||||
}),
|
||||
]),
|
||||
});
|
||||
|
||||
export const AgentForkContextResponseMessageSchema = z.object({
|
||||
type: z.literal("agent.fork_context.response"),
|
||||
payload: z.object({
|
||||
@@ -4207,6 +4309,9 @@ export const SessionOutboundMessageSchema = z.discriminatedUnion("type", [
|
||||
ArchiveWorkspaceResponseMessageSchema,
|
||||
FetchAgentResponseMessageSchema,
|
||||
FetchAgentTimelineResponseMessageSchema,
|
||||
ProviderSubagentListResponseMessageSchema,
|
||||
ProviderSubagentTimelineResponseMessageSchema,
|
||||
ProviderSubagentUpdateMessageSchema,
|
||||
AgentForkContextResponseMessageSchema,
|
||||
CancelAgentResponseMessageSchema,
|
||||
ClearAgentAttentionResponseMessageSchema,
|
||||
@@ -4679,6 +4784,7 @@ export const WSHelloMessageSchema = z.object({
|
||||
[CLIENT_CAPS.reasoningMergeEnum]: z.boolean().optional(),
|
||||
[CLIENT_CAPS.customModeIcons]: z.boolean().optional(),
|
||||
[CLIENT_CAPS.terminalReflowableSnapshot]: z.boolean().optional(),
|
||||
[CLIENT_CAPS.providerSubagents]: z.boolean().optional(),
|
||||
[CLIENT_CAPS.browserHost]: BrowserAutomationHostCapabilitySchema.optional(),
|
||||
})
|
||||
.passthrough()
|
||||
|
||||
Reference in New Issue
Block a user