Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
c7efecb
docs: prepare cross-platform session integration branch
haesookimDev Sep 23, 2026
3f51273
feat: define canonical agent focus replay contract
haesookimDev Sep 27, 2026
9041653
Merge pull request #54 from PlateerLab/feat/cross-platform-agent-focu…
haesookimDev Sep 27, 2026
62aeea4
Define canonical Agent Session event replay contract
haesookimDev Sep 29, 2026
3fbd3d7
Merge pull request #55 from PlateerLab/feat/cross-platform-agent-even…
haesookimDev Sep 29, 2026
f26d1e5
feat: define linked Agent Session message page contract
haesookimDev Sep 30, 2026
e4c8f03
Merge pull request #57 from PlateerLab/feat/cross-platform-linked-mes…
haesookimDev Sep 30, 2026
5eb1c35
feat(agent-session): add scoped immutable attachment contracts
haesookimDev Oct 6, 2026
308594b
fix(agent-session): detach raw validation error context
haesookimDev Oct 6, 2026
2d646dc
Merge pull request #60 from PlateerLab/feat/cross-platform-attachment…
haesookimDev Oct 6, 2026
fc507f5
feat: canonical 첨부 턴 제출 SDK 계약 추가
haesookimDev Oct 6, 2026
8dea4bc
feat: 첨부 턴 JSON Schema에 참조 개수 상한 명시
haesookimDev Oct 6, 2026
0c5e853
Merge pull request #61 from PlateerLab/feat/cross-platform-attachment…
haesookimDev Oct 6, 2026
6a5e355
기준 브랜치 동기화와 플랫폼 인증·세션 충돌 정리
haesookimDev Oct 15, 2026
8dee04a
Merge pull request #66 from PlateerLab/feat/cross-platform-base-sync-…
haesookimDev Oct 15, 2026
1496ee9
feat: 정본 턴 상태 조회 SDK 계약과 클라이언트 추가
haesookimDev Oct 15, 2026
53c5988
Merge PR #67: 정본 턴 상태 조회 SDK 연결
haesookimDev Oct 15, 2026
2adb467
턴별 broker 작업 조회와 취소 SDK 연결
haesookimDev Oct 15, 2026
84e3fb4
Merge pull request #68 from PlateerLab/feat/cross-platform-turn-broke…
haesookimDev Oct 15, 2026
2050d03
기기 capability 실행 승인 행위를 정식 카탈로그에 추가
haesookimDev Oct 17, 2026
991ab9e
Merge pull request #72 from PlateerLab/feat/cross-platform-cluster-ca…
haesookimDev Oct 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions .github/workflows/agent-session-contracts.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Agent Session contracts

on:
pull_request:
paths:
- 'src/xgen_sdk/agent_session/**'
- 'tests/test_agent_session_*.py'
- 'tests/fixtures/agent-session-*.json'
- '.github/workflows/agent-session-contracts.yml'
- 'pyproject.toml'
push:
branches:
- 'feat/cross-platform-*'
paths:
- 'src/xgen_sdk/agent_session/**'
- 'tests/test_agent_session_*.py'
- 'tests/fixtures/agent-session-*.json'
- '.github/workflows/agent-session-contracts.yml'
- 'pyproject.toml'

permissions:
contents: read

jobs:
contracts:
name: Contracts (Python ${{ matrix.python }})
runs-on: ubuntu-latest
strategy:
matrix:
python: ['3.11', '3.12']
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}
- name: Install contract test dependencies
run: python -m pip install 'pydantic>=2,<3' pytest
- name: Verify isolated unreleased source contracts
env:
PYTHONPATH: src
# Approval registry fixtures are unrelated to these pure wire models.
run: python -m pytest --noconftest -q tests/test_agent_session_*.py
68 changes: 68 additions & 0 deletions docs/agent-session-broker-operations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Agent Session broker 작업 클라이언트 / Agent Session broker operation clients

## 범위 / Boundary

`AgentSessionBrokerOperationsClient`는 소유한 Agent Session 턴에 연결된 broker 작업의 공개 참조를 나열하고, 한 작업의 공개 metadata를 읽고, 취소를 접수하는 순수 SDK 클라이언트다. 호출자가 인증된 JSON GET과 빈 본문 JSON POST callback을 주입한다. SDK는 credential, base URL, 환경변수, HTTP 인증, retry, polling, 실행, reconcile 또는 수명 연장을 소유하지 않는다.

`AgentSessionBrokerOperationsClient` is a pure SDK client for listing public broker-operation references attached to an owned Agent Session turn, reading public metadata for one operation, and requesting cancellation. The caller injects authenticated JSON GET and empty-body JSON POST callbacks. The SDK owns no credentials, base URL, environment variables, HTTP authentication, retry, polling, execution, reconciliation, or lifetime extension.

## 고정 API / Fixed API

| SDK method | HTTP contract | Public response |
|---|---|---|
| `list(session_id, turn_id)` | `GET /api/agentflow/agent-sessions/{session_id}/turns/{turn_id}/operations` | bare array, maximum 128 exact references |
| `read(session_id, turn_id, reference)` | `GET .../operations/{invocation_id}` | exact seven-field metadata |
| `cancel(session_id, turn_id, reference)` | `POST .../operations/{invocation_id}/cancel`, empty body, HTTP 202 | exact cancellation acknowledgement |

모든 경로는 query가 없다. callback은 `get(path)`와 `post(path)`처럼 경로 인자 하나만 받는다. 특히 `post`에 JSON, 빈 객체, `None`, header 또는 query를 전달하지 않는다. 호출자 transport는 현재 Platform Session/DPoP, HTTPS origin, 응답 크기와 timeout, HTTP status를 처리하고 성공 JSON만 반환해야 한다. SDK는 callback을 한 번만 호출하며 transport 예외와 task cancellation을 그대로 전달한다.

Every path is queryless. Each callback accepts one path argument as `get(path)` or `post(path)`. In particular, the SDK passes no JSON, empty object, `None`, headers, or query to `post`. The caller transport handles the current Platform Session/DPoP, HTTPS origin, response size and timeout, and HTTP status, then returns successful JSON. The SDK calls the callback once and propagates transport errors and task cancellation unchanged.

```python
from xgen_sdk.agent_session import AgentSessionBrokerOperationsClient

# Both callbacks authenticate with the caller's current session.
# authenticated_empty_json_post(path) sends an HTTP request with zero body bytes.
client = AgentSessionBrokerOperationsClient(
authenticated_json_get,
authenticated_empty_json_post,
)

references = await client.list(session_id, turn_id)
if references:
metadata = await client.read(session_id, turn_id, references[0])
accepted = await client.cancel(session_id, turn_id, references[0])
```

## 공개 DTO와 검증 / Public DTOs and validation

세션, 턴, invocation ID는 nonzero UUID를 lower canonical 문자열로 직렬화했을 때 입력과 정확히 같아야 한다. SDK는 세션과 턴 ID를 transport 호출 전에 검사한다. 참조 목록은 정확한 기본 JSON 배열이어야 하며 최대 128개이고 invocation ID가 고유해야 한다. 반환한 Python tuple과 모든 DTO는 불변이다. 추가 필드, coercion, model subclass, `model_construct`/`model_copy` 우회 값은 parser에서 다시 검사한다.

Session, turn, and invocation identifiers must be nonzero UUIDs whose lower canonical string exactly equals the input. The SDK validates session and turn identifiers before transport. A reference list must be an exact plain JSON array with at most 128 entries and unique invocation identifiers. The returned Python tuple and every DTO are immutable. Parsers revalidate extra fields, coercion, model subclasses, and values forged through `model_construct` or `model_copy`.

참조는 정확히 `invocation_id`, `operation_id`만 가진다. 허용 operation은 다음 여섯 개다.

A reference contains exactly `invocation_id` and `operation_id`. The operation allowlist is:

- `documents.collections.list`
- `documents.collection.documents.list`
- `workflow.actor.authorize`
- `documents.attachment.index`
- `workflow.code.execute`
- `workflow.attachments.stage`

Metadata는 정확히 `invocation_id`, `operation_id`, `state`, `cancel_requested`, `target_cleanup`, `result_available`, `expires_at`만 가진다. `read`는 응답의 invocation과 operation을 모두 호출자가 보존한 expected reference에 묶는다. `state`는 `running`, `completed`, `failed`, `cancelled`, `unknown` 중 하나다. `expires_at`은 1 이상 JavaScript safe integer 이하의 strict integer이며 bool을 거부한다.

Metadata contains exactly `invocation_id`, `operation_id`, `state`, `cancel_requested`, `target_cleanup`, `result_available`, and `expires_at`. `read` binds both response invocation and operation to the caller-retained expected reference. `state` is one of `running`, `completed`, `failed`, `cancelled`, or `unknown`. `expires_at` is a strict integer from 1 through the JavaScript safe-integer maximum; booleans are rejected.

`workflow.code.execute`와 `workflow.attachments.stage`만 Sandbox 작업이다. Sandbox의 `target_cleanup`은 `pending`, `complete`, `unknown` 중 하나이고 `not_applicable`은 금지된다. 다른 네 operation은 `not_applicable`이어야 한다. `result_available=true`는 Sandbox 작업이 `completed`일 때만 허용한다. 공개 metadata에는 결과 본문이 없으며 `result`, grant, lease, 입력 body 같은 private 필드를 거부한다.

Only `workflow.code.execute` and `workflow.attachments.stage` are Sandbox operations. Their `target_cleanup` is `pending`, `complete`, or `unknown`; `not_applicable` is forbidden. The other four operations require `not_applicable`. `result_available=true` is allowed only for a completed Sandbox operation. Public metadata contains no result body and rejects private fields such as `result`, grants, leases, or input bodies.

취소 응답은 정확히 `invocation_id`와 `cancel_requested: true`만 가진다. 이것은 HTTP 202 접수 증거다. 최종 state, process 종료, stage 삭제 또는 `target_cleanup=complete`를 뜻하지 않는다. 정리 상태는 이후 명시적인 `read` 응답에서만 판단한다.

A cancellation response contains exactly `invocation_id` and `cancel_requested: true`. This is HTTP 202 acceptance evidence. It does not mean a final state, process termination, stage deletion, or `target_cleanup=complete`. Cleanup is interpreted only from a later explicit `read` response.

검증 실패는 원시 payload와 exception context를 노출하지 않는 고정 `AgentSessionBrokerOperationValidationError`다. 공개 fixture `tests/fixtures/agent-session-broker-operations.json`은 SDK와 Frontend가 같은 유효·변조 벡터를 사용하도록 하며 credential, grant, lease 또는 실제 결과를 포함하지 않는다.

Validation failures use a fixed `AgentSessionBrokerOperationValidationError` without raw payload or exception context. The public fixture at `tests/fixtures/agent-session-broker-operations.json` lets SDK and Frontend consume the same valid and tampered vectors and contains no credential, grant, lease, or real result.
57 changes: 57 additions & 0 deletions docs/canonical-attachment-reference-contract.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Canonical 첨부 참조 계약 / Canonical attachment reference contract

## 현재 구현 범위 / Current boundary

이 계약은 Canonical 업로드·턴 연결을 위한 **메타데이터 검증 기반**이다. 아직 업로드 API, 저장소, 저널 연결, 다운로드 또는 첨부 UI를 제공하지 않는다. 현재 Canonical 턴 API는 텍스트 전용이며 `attachments`를 거부한다. Legacy workspace 업로드를 자동으로 대신 호출하지 않는다.

This is the metadata validation foundation for future Canonical upload and turn linking. Upload/storage/journal/download/UI integration is not implemented. Current Canonical turn requests remain text-only and reject `attachments`; no legacy workspace fallback is enabled.

## 데이터 / Data

Scope는 검증된 로그인과 선택 세션에서 얻는다. Receipt는 향후 서버가 저장을 완료한 첨부의 응답 형식이다. 이를 파싱했다는 사실은 발급·소유권·접근권한·실제 bytes의 checksum을 검증했다는 뜻이 아니다. 서버는 Gateway가 검증한 principal로 저장된 첨부의 계정·세션·workflow와 실제 checksum을 다시 검사해야 한다.

Scope comes from the authenticated login and selected session. A receipt describes a future server-committed attachment. Shape validation cannot prove issuance, ownership, access or the checksum of stored bytes. The server must independently verify these against the Gateway-verified principal and stored attachment before execution.

| 필드 / Field | 타입 / Type | 제약과 용도 / Constraint and use |
|---|---|---|
| `origin` | string | 정규 HTTPS origin, 경로·사용자정보·query·fragment 없음. 소문자 ASCII DNS (`xn--` IDN 제외), canonical IPv4/IPv6; 포트 1..65535, 기본 443 생략. / Canonical HTTPS origin; ASCII DNS excluding IDN A-labels, or canonical IP; no paths, credentials, query or fragment. |
| `user_id` | string | `1`..`9223372036854775807`의 정규 십진 문자열. 앞의 0·숫자 coercion 없음. / Positive canonical decimal string, no numeric coercion. |
| `session_id` | string | 서버 발급 Canonical 세션의 소문자 UUID, version 1..8, RFC variant. / Lowercase canonical session UUID. |
| `workflow_id` | string | 원문 Unicode / Raw Unicode, UTF-8 1..128 bytes, slash/backslash·C0/C1·방향 제어 문자 없음. / Bounded Unicode identifier; no paths or control characters. |
| `attachment_id` | string | 서버가 발급할 opaque 소문자 UUID, version 1..8, RFC variant. 클라이언트가 저장 경로를 선택하지 않는다. / Opaque server-issued UUID; no client storage path. |
| `filename` | string | 원문 Unicode / Raw Unicode basename, UTF-8 1..255 bytes; slash/backslash·C0/C1·방향 제어 문자와 `.`/`..` 금지. 저장 경로로 사용하지 않는다. / Display basename, never a storage path. |
| `size_bytes` | integer | 0..104857600, bool·문자열·소수 coercion 없음. / Strict integer, 0..100 MiB. |
| `media_type` | string | 소문자 `type/subtype` 토큰, 최대255 ASCII bytes, parameter 없음. 표시 메타데이터이며 이미지 검증 결과가 아니다. / Inert MIME hint, not verified file content. |
| `sha256` | string | 소문자 64자리 hex. 실제 파일의 서버 checksum과 일치해야 한다. / Lowercase 64-character hex; must match stored server checksum. |

- Scope에는 첫 4개 필드만 있고 receipt에는 표의 9개 필드만 있다. 추가 필드는 거부한다.
- 미래 턴 참조에는 `attachment_id`, `sha256`만 있다. 경로·URL·base64·bytes·권한/신뢰 주장·표시 힌트를 전달하지 않는다.
- 최대10개, 파일당100 MiB, 합계100 MiB이다. 중복 ID는 checksum이 같아도 거부하며 순서는 유지한다. 이 상한은 현재 서버의 허용 업로드 정책을 선언하지 않는다. 실제 업로드 및 이미지 sniffing/decoder 제한은 서버 구현에서 별도로 적용해야 한다.
- TypeScript는 새 primitive-only 객체와 배열을 freeze한다. Python은 frozen 모델과 tuple을 반환한다. 원본 receipt 목록을 수정해도 준비된 참조는 바뀌지 않는다.
- 계정·origin·세션·workflow가 바뀌면 draft와 준비된 참조를 폐기한다. 응답 유실 후 재시도는 원래 참조의 **순서·ID·checksum**을 유지해야 하며, 후속 턴 저널 구현이 이를 idempotency hash에 포함해야 한다.

IDN A-labels are reserved until both languages share an IDNA normalization contract. Scopes accept only their four fields; receipts accept only the nine fields above. Future turn references contain only `attachment_id` and `sha256`. Up to ten ordered, unique IDs are accepted, with 100 MiB per-file and aggregate caps. These local caps do not authorize uploads; server content sniffing, image decoder and storage policies remain separate. Results are copied and frozen (TypeScript objects/array, Python models/tuple). Scope changes must discard prepared drafts. Future journal hashing and explicit unknown-outcome retries must preserve the exact ordered ID/checksum list.

Unicode 원문은 정규화하지 않고 code point와 UTF-8 상한을 그대로 보존한다. 서버에서 얻은 workflow와 정확한 문자열로 비교하므로 NFC/NFD 표현이 다르면 scope도 다르다. 런타임별 Unicode 정규화 테이블에 의존하지 않는다. / Unicode metadata is preserved verbatim without normalization; distinct NFC/NFD workflow strings remain distinct scope values.

## 제공 함수 / Helpers

| DEX protocol | Python SDK | 동작 / Behavior |
|---|---|---|
| `parseAgentAttachmentScope(value)` | `parse_attachment_scope(value)` | Scope를 엄격히 검사하고 복사한다. / Validate and copy context. |
| `parseAgentAttachmentReceipt(value, scope)` | `parse_attachment_receipt(value, scope)` | 전체 구조·범위·scope 동등성을 검사한다. / Validate receipt and exact scope match. |
| `prepareAgentAttachmentReferences(receipts, scope)` | `prepare_attachment_references(receipts, scope)` | 중복·개수·합계 제한을 검사하고 불변 참조 목록을 만든다. / Prepare immutable ordered references. |

Python 모델은 `AgentAttachmentScope`, `AgentAttachmentReceipt`, `AgentAttachmentReference`이다. TypeScript는 같은 이름의 interface를 제공한다. helper 실패는 원시 입력을 포함하지 않는 `AgentAttachmentValidationError`를 반환한다. 현재 endpoint는 이 모델을 수용하지 않으며 SDK는 네트워크 요청을 수행하지 않는다.

Both implementations expose the same named models/interfaces. Helper failures produce a generic `AgentAttachmentValidationError` without raw input. The current endpoint does not accept these models and the SDK performs no network requests.

## 다음 연결 순서 / Next integration steps

1. 서버 소유권·durable storage·checksum을 검증하는 Canonical 업로드와 정리/보존 정책.
2. 첨부 참조를 정확한 순서로 턴 request hash와 저널에 묶고 원자적으로 예약하는 계약.
3. 검증된 내부 실행 전달 및 안전한 다운로드/완료 메시지 projection.
4. Native host의 동일 인증 lock·scope 폐기·명시적 원본 재시도와 각 클라이언트 UI.
5. 실제 ACTIVE Gateway와 pod 재시작·계정 변경·cross-surface 파일 송신 검증.

Implement server-owned durable upload and retention first, then ordered journal/hash binding, verified execution/download projection, native/UI integration and actual ACTIVE cross-surface/pod recovery checks. The pure contract tests do not replace these gates.
Loading
Loading