Add attachment owner lookup to the app-server (#50094)

## Why

`thread/attachment/list` lists attachments for a known thread. Clients also need to find the threads associated with a given attachment identity.

## What changed

Add `thread/attachmentOwner/list` to return owning thread IDs and archive status for an exact `attachmentType` and `identityKey`. Support cursor pagination and an optional `archived` filter, including both archived and non-archived threads by default.

Wire the request through the thread store and update documentation, protocol schemas, and generated TypeScript and Python types. The lookup is limited to the configured thread store and reports current membership, not an atomic resource-cleanup check.

## Testing

Extend app-server integration tests to cover exact type-and-key matching, multiple owners, archive filtering, and invalid cursor rejection.

GitOrigin-RevId: 30f4a20e00243d0023246d465a9b95213b3adeb6
This commit is contained in:
joeytrasatti-openai
2026-10-01 20:47:05 +00:00
committed by copyberry
parent 9d53dd91b5
commit 2635431edb
24 changed files with 694 additions and 2 deletions
@@ -5169,6 +5169,43 @@ class ThreadAttachmentOperation(Enum):
deleted = "deleted"
class ThreadAttachmentOwner(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
archived: Annotated[
bool,
Field(
description="Whether the owning thread is archived, not whether it is currently executing a turn."
),
]
thread_id: Annotated[str, Field(alias="threadId")]
class ThreadAttachmentOwnerListParams(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
archived: Annotated[
bool | None,
Field(
description="Omitted or null returns all matches; false returns non-archived threads only."
),
] = None
attachment_type: Annotated[str, Field(alias="attachmentType")]
cursor: str | None = None
identity_key: Annotated[str, Field(alias="identityKey")]
limit: Annotated[int | None, Field(ge=0)] = None
class ThreadAttachmentOwnerListResponse(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
data: list[ThreadAttachmentOwner]
next_cursor: Annotated[str | None, Field(alias="nextCursor")] = None
class ThreadAttachmentRemoveParams(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
@@ -6907,6 +6944,18 @@ class ThreadAttachmentListRequest(BaseModel):
params: ThreadAttachmentListParams
class ThreadAttachmentOwnerListRequest(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
id: RequestId
method: Annotated[
Literal["thread/attachmentOwner/list"],
Field(title="Thread/attachmentOwner/listRequestMethod"),
]
params: ThreadAttachmentOwnerListParams
class ThreadAttachmentRemoveRequest(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
@@ -12545,6 +12594,7 @@ class ClientRequest(
| ThreadMetadataUpdateRequest
| ThreadAttachmentAddRequest
| ThreadAttachmentListRequest
| ThreadAttachmentOwnerListRequest
| ThreadAttachmentRemoveRequest
| ThreadSectionMoveRequest
| ThreadUnarchiveRequest
@@ -12655,6 +12705,7 @@ class ClientRequest(
| ThreadMetadataUpdateRequest
| ThreadAttachmentAddRequest
| ThreadAttachmentListRequest
| ThreadAttachmentOwnerListRequest
| ThreadAttachmentRemoveRequest
| ThreadSectionMoveRequest
| ThreadUnarchiveRequest