github / github/copilot-sdk

Support resumable sub-agent conversations (stateful custom agents)

Đang mở
#2,111 0 bình luận 0 reaction 0 người được giao Xem trên GitHub
enhancement
Ngôn ngữ chính
Java
Star
10.5k
Fork
1.5k
Merge trung bình
1 ngày 11 giờ
Pull request đã merge (30 ngày)
128

Mô tả

Custom sub-agents (CustomAgentConfig) are stateless per invocation. Each delegation starts a
fresh context, and there is no supported way to persist a sub-agent's conversation or resume a
previous sub-agent run. I'd like to request first-class support for **stateful (resumable)
sub-agents. Notably, the SDK already models a sub-agent task identity internally — it just isn't addressable
by callers (see "Current behavior" below). The ask is largely to expose what already exists.

We're building a multi-agent platform where a routing agent delegates to a catalog of
specialist sub-agents that are materialized dynamically per request. In practice, users
converse with a specialist across several turns:

Turn 1: "Show me my accounts."
→ routed to the Accounts specialist, which fetches and reasons over the result set.
>
Turn 2: "Now get the health scores for those."
→ routed to the same specialist, which no longer has any memory of "those."

Because each delegation is a cold start, the second turn either (a) redundantly re-runs the
first specialist's tool calls, or (b) fails because the referent is gone. We currently work
around this by having the parent re-serialize prior context into every delegation prompt, which:

inflates token cost — the same context is re-sent on every turn;
is lossy — the parent must guess what the specialist needs, and can only forward what it
happened to observe;
duplicates side effects — the specialist re-issues tool calls it already made;
doesn't scale with depth or turn count — the re-serialized preamble grows monotonically.

This is the central limitation we hit when using sub-agents for anything beyond single-shot,
fire-and-forget tasks.

CustomAgentConfig has no state, persistence, or session field (session.py:979-994):

```
class CustomAgentConfig(TypedDict, total=False):
name: str
display_name: NotRequired[str]
description: NotRequired[str]
tools: NotRequired[list[str] | None]
prompt: str
mcp_servers: NotRequired[dict[str, MCPServerConfig]]
infer: NotRequired[bool]
skills: NotRequired[list[str]]
model: NotRequired[str]
```

There is no field to opt a sub-agent into persistence, and nowhere to attach a checkpointer or
store.

2. Session.send() has no way to target a prior sub-agent run (session.py:1261-1270):

```
async def send(
self,
prompt: str,
*,
attachments: list[Attachment] | None = None,
mode: Literal["enqueue", "immediate"] | None = None,
agent_mode: Literal["interactive", "plan", "autopilot", "shell"] | None = None,
request_headers: dict[str, str] | None = None,
display_prompt: str | None = None,
) -> str:
```

3. A sub-agent task identifier already exists — but is inbound-only.
parentAgentTaskId appears on UserMessageData (generated/session_events.py:6743), so the
runtime clearly tracks which agent task a message belongs to. It is only ever read off an
observed event; there is no corresponding parameter to pass one back in.

For completeness, the persistence primitives that do exist are all session-scoped and cannot
be applied to an individual sub-agent:

Proposal

Two shapes, in increasing order of scope. Either would unblock us; Option A looks like the
smaller change given that the identifier already exists.

Option A — expose the existing agent task ID (minimal)

Make parentAgentTaskId round-trippable, and let a sub-agent opt into retention:

```
# opt in per sub-agent
CustomAgentConfig(
name="accounts-specialist",
prompt=...,
persist_conversation=True, # NEW: retain this agent's context across invocations
)

# address a prior run
await session.send(
"Now get health scores for those accounts.",
resume_agent_task_id=prior_task_id, # NEW
)
```

Retention could reasonably be scoped to the parent session's lifetime, which sidesteps any new
durable-storage requirements.

Option B — first-class sub-agent handles

Surface a handle when a sub-agent is invoked and allow direct continuation:
```
handle = await session.get_agent_task(task_id)
await handle.send("Now get health scores for those accounts.")
```
This is more expressive (it also enables inspecting a sub-agent's transcript) but is a larger
API surface.

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Hướng nghiên cứu

Start by tracing CustomAgentConfig and Session.send() in session.py, then inspect parentAgentTaskId in generated/session_events.py. Compare the proposed task-ID parameter and handle-based API, including how retention would be scoped to a parent session. Done means selecting and specifying a coherent resumable sub-agent API rather than implementing only one isolated field.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
python
Lĩnh vực
backend-api-design, devtools
Loại issue
Tính năng
Độ khó
5/5
Thời gian dự kiến
Hơn một tuần
Mức độ hoạt động
Ít trao đổi
Độ rõ ràng
Khá rõ ràng
Mức phù hợp với người mới
45/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.