# 클라우드 세션

클라우드 세션은 Mission Control을 통해 GitHub에서 호스팅되는 컴퓨팅 리소스에서 Copilot 작업을 실행합니다. 앱이 사용자의 컴퓨터 또는 서버에서 로컬 Copilot CLI 세션을 시작하는 대신 원격으로 실행되는 세션을 만들어야 할 때 사용합니다.

<!-- markdownlint-disable GHD046 GHD005 -->

<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->

## 사전 요구 사항

클라우드 세션을 만들기 전에 다음을 확인합니다.

* 사용자에게 클라우드 에이전트 자격으로 Copilot 액세스 권한이 있습니다.
* 세션은 사용자 토큰 또는 로그인한 Copilot CLI ID를 사용하여 GitHub 인증할 수 있습니다.
* 세션을 GitHub 리포지토리와 연결할 수 있습니다. SDK 유형에서는 선택 사항이지만 Mission Control 및 클라우드 에이전트에 리포지토리 컨텍스트가 있도록 권장됩니다.
* 조직 정책을 사용하면 클라우드 화면에서 원격 제어 및 세션을 볼 수 있습니다.

## 클라우드 세션 만들기

클라우드 세션을 만들려면 세션 `cloud` 만들기 옵션을 설정합니다. 리포지토리 메타데이터를 포함하여 클라우드 세션을 GitHub 리포지토리와 연결할 수 있습니다.

<!-- tabs:start -->

### TypeScript

```typescript
import { CopilotClient } from "@github/copilot-sdk";

const client = new CopilotClient();
await client.start();

const session = await client.createSession({
  onPermissionRequest: async () => ({ kind: "approve-once" }),
  cloud: {
    repository: {
      owner: "github",
      name: "copilot-sdk",
      branch: "main",
    },
  },
});
```

### Python

```python
from copilot import (
    CloudSessionOptions,
    CloudSessionRepository,
    CopilotClient,
    PermissionHandler,
)

client = CopilotClient()
await client.start()

session = await client.create_session(
    on_permission_request=PermissionHandler.approve_all,
    cloud=CloudSessionOptions(
        repository=CloudSessionRepository(
            owner="github",
            name="copilot-sdk",
            branch="main",
        )
    ),
)
```

### 이동

```golang
client := copilot.NewClient(nil)
if err := client.Start(ctx); err != nil {
    return err
}

session, err := client.CreateSession(ctx, &copilot.SessionConfig{
    Cloud: &copilot.CloudSessionOptions{
        Repository: &copilot.CloudSessionRepository{
            Owner:  "github",
            Name:   "copilot-sdk",
            Branch: "main",
        },
    },
    OnPermissionRequest: func(req copilot.PermissionRequest, inv copilot.PermissionInvocation) (rpc.PermissionDecision, error) {
        return &rpc.PermissionDecisionApproveOnce{}, nil
    },
})
_ = session
```

### .NET

```csharp
await using var client = new CopilotClient();

var session = await client.CreateSessionAsync(new SessionConfig
{
    Cloud = new CloudSessionOptions
    {
        Repository = new CloudSessionRepository
        {
            Owner = "github",
            Name = "copilot-sdk",
            Branch = "main",
        },
    },
    OnPermissionRequest = (req, inv) =>
        Task.FromResult(PermissionDecision.ApproveOnce()),
});
```

### Java

```java
import com.github.copilot.CopilotClient;
import com.github.copilot.rpc.*;

try (var client = new CopilotClient()) {
    client.start().get();

    var session = client.createSession(
        new SessionConfig()
            .setCloud(new CloudSessionOptions()
                .setRepository(new CloudSessionRepository()
                    .setOwner("github")
                    .setName("copilot-sdk")
                    .setBranch("main")))
            .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
    ).get();
}
```

### 러스트

```rust
use std::sync::Arc;
use github_copilot_sdk::{CloudSessionOptions, CloudSessionRepository, SessionConfig};
use github_copilot_sdk::handler::ApproveAllHandler;

let session = client.create_session(
    SessionConfig::default()
        .with_cloud(CloudSessionOptions::with_repository(
            CloudSessionRepository::new("github", "copilot-sdk").with_branch("main"),
        ))
        .with_permission_handler(Arc::new(ApproveAllHandler)),
).await?;
```

<!-- tabs:end -->

## 첫 번째 프롬프트 보내기

클라우드 세션은 두 단계로 초기화됩니다: `createSession`는 Mission Control이 작업을 예약하는 즉시 처리되지만, 원격 `copilot-agent` 워커가 연결되어 `session.start`를 내보내기까지는 1\~2초가 더 걸립니다. 그 전에 `session.send`을(를) 호출하면 런타임의 `RemoteSession.send`이(가) `"Remote session is still starting"`을(를) 발생시키지만, 스키마 래퍼는 fire-and-forget 방식이라 **오류를 조용히 처리하면서도** 여전히 코드에 새 `messageId`을(를) 반환합니다. 프롬프트가 서버에서 삭제되고 작업자에게 도달하지 않습니다.

안정적으로 보내려면 보내기 **전에** 이벤트를 구독하고 다음과 같은 `session.start``producer`첫 번째 `"copilot-agent"` 이벤트를 기다립니다.

<!-- docs-validate: skip -->

```typescript
import { CopilotClient, type CopilotSession } from "@github/copilot-sdk";

const client = new CopilotClient();
await client.start();

const session: CopilotSession = await client.createSession({
  streaming: true, // required for assistant.message_delta to fire
  cloud: { repository: { owner: "github", name: "copilot-sdk" } },
  onPermissionRequest: async () => ({ kind: "approve-once" }),
});

// Subscribe BEFORE sending so you don't miss the start event.
const ready = new Promise<void>((resolve) => {
  const off = session.on("session.start", (event) => {
    if (event.data?.producer === "copilot-agent") {
      off();
      resolve();
    }
  });
});

await ready;
await session.send({ prompt: "Summarize the README" });
```

몇 가지 참고 사항:

* 런타임이 `streaming: true` 이벤트를 내보내도록 `createSession`에서 `assistant.message_delta`을 설정합니다. 이 신호가 없으면 받을 수 있는 어시스턴트 신호는 마지막 `assistant.message`뿐입니다. 배치 처리에는 괜찮지만, 실시간 UI를 렌더링하고 있다면 채팅이 멈춘 것처럼 보일 것입니다.
  [스트리밍 세션 이벤트](/ko/copilot/how-tos/copilot-sdk/features/streaming-events)을(를) 참조하세요.
* 오직 **첫 번째**`session.send`만 이 경쟁 상태의 영향을 받습니다. 런타임이 세션 수명 동안 설정된 상태이므로 `hasSessionStarted` 동일한 세션에 대한 후속 전송은 정상적으로 작동합니다.
* 중단된 Mission Control 프로비저닝이 앱을 영원히 중단하지 않도록 `ready` 프라미스 주위에 시간 제한(예: 60s)을 적용합니다.
* 동일한 패턴은 모든 SDK 언어에 동일하게 적용됩니다. `session.start`을 구독하고, `producer === "copilot-agent"`을 확인한 다음, `send`를 호출합니다.

## Mission Control URL에 접속하기

클라우드 세션은 기본적으로 원격입니다. 작업자가 연결되면 Mission Control에서 `https://github.com/copilot/tasks/{sessionId}` 세션을 게시하고 런타임에서 URL을 사용하여 `session.info` 이벤트를 내보냅니다. 호출할 \*\*\*\* 필요가 `remote.enable()`. API는 로컬 세션을 Mission Control으로 승격하기 위한 것입니다.

URL을 캡처하려면 `session.info`을(를) 구독하고 `infoType: "remote"`으로 필터링하세요:

<!-- docs-validate: skip -->

```typescript
session.on("session.info", (event) => {
  if (event.data?.infoType === "remote" && event.data.url) {
    console.log("Open from web or mobile:", event.data.url);
    // For example, surface in your UI as a shareable link or QR code.
  }
});
```

이 이벤트는 `session.start` 직후에 실행됩니다. 렌더러가 이벤트가 이미 발생한 뒤에 마운트되는 경우, 앱 상태에 세션 레코드와 함께 URL을 저장하고 다시 마운트될 때 리하이드레이션하세요. 런타임은 자체적으로 `session.info`를 다시 내보내지 않습니다.

`remote: true`를 통해 승격된 로컬 세션의 동일한 배선에 대해서는 [원격 세션](/ko/copilot/how-tos/copilot-sdk/features/remote-sessions)을 참조하세요.

## 리포지토리 연결

`cloud.repository` 개체는 클라우드 세션을 GitHub 리포지토리와 연결합니다.

| Field    | 필수  | Description                                                           |
| -------- | --- | --------------------------------------------------------------------- |
| `owner`  | Yes | 리포지토리 소유자 또는 조직.                                                      |
| `name`   | Yes | 리포지토리 이름입니다.                                                          |
| `branch` | No  | 리포지토리 컨텍스트에 사용할 분기입니다. 런타임에서 기본 분기 또는 현재 리포지토리 컨텍스트를 선택할 수 있도록 생략합니다. |

리포지토리 연결은 SDK 형식에서 선택 사항이지만 앱이 대상 리포지토리를 알 때마다 포함합니다. 이를 통해 Mission Control은 올바른 컨텍스트에서 세션을 표시하고 클라우드 에이전트에 보다 명확한 시작점을 제공합니다.

특정 분기에서 작업을 시작해야 하는 경우에 사용합니다 `branch` . 앱이 풀 리퀘스트, 이슈 분류 흐름 또는 배포 워크플로에서 세션을 생성하는 경우, 사용자에게 표시되는 작업에 해당하는 브랜치를 전달하세요.

## 클라우드 세션 다시 열기

이 옵션은 `cloud` 새 세션을 만들 때만 적용됩니다. 기존 클라우드 세션을 다시 시작하려면 SDK 언어에 대한 표준 다시 시작 API를 사용합니다.

```typescript
const session = await client.resumeSession("session-id", {
  onPermissionRequest: async () => ({ kind: "approve-once" }),
});
```

다시 시작할 때는 `cloud`를 다시 전달하지 마세요. 저장된 세션 메타데이터는 세션이 클라우드 지원임을 확인하고 다시 시작은 일반 세션 다시 시작 경로를 따릅니다.

## 조직 정책 및 자격

사용자 또는 조직이 클라우드 에이전트 실행을 받을 자격이 없거나 조직 수준 정책이 흐름을 차단하는 경우 클라우드 세션 생성이 실패할 수 있습니다. 특히 클라우드 샌드박스에 대한 정책은 클라이언트가 클라우드 작업을 만들지 못하게 할 수 있습니다.

이 경우 런타임은 클라우드 작업 생성에 대해 `"policy_blocked"` 실패 사유를 보고합니다. 일시적인 인프라 오류가 아닌 권한 부여 또는 정책 결과로 처리합니다.

TypeScript에서 다시 시도하기 전에 이유를 확인합니다.

```typescript
try {
  await client.createSession({ cloud: { repository } });
} catch (error) {
  if ((error as { reason?: string }).reason === "policy_blocked") {
    // Show an admin-facing message or link to org policy settings.
  }
  throw error;
}
```

SDK 오류가 다르게 표시되는 언어에서는 표시된 오류 원인이나 코드를 검사하고 `"policy_blocked"`를 명시적으로 처리합니다. 정책 변경 없이 재시도는 성공하지 못할 것으로 예상됩니다.

## 통합 ID 및 라우팅

클라우드 세션은 `Copilot-Integration-Id` 환경 변수에서 파생된 `GITHUB_COPILOT_INTEGRATION_ID` 헤더로 스탬프됩니다. 이 통합 ID는 Mission Control에서 라우팅, 어트리뷰션 및 통합별 동작을 위해 사용됩니다.

다중 사용자 서버 지침 및 전체 통합 ID 세부 정보는 [다중 테넌트 및 서버 배포](/ko/copilot/how-tos/copilot-sdk/setup/multi-tenancy)을 참조하세요.

Mission Control은 SDK로 생성된 클라우드 세션을 `copilot-developer-sandbox` 에이전트 슬러그로 라우팅합니다. 이름은 클라우드 에이전트에 대한 내부 라우팅 슬러그이며 세션이 로컬 Windows 샌드박스를 사용하는 것을 의미하지는 않습니다.

## 고급: `COPILOT_MC_BASE_URL`

기본적으로 런타임은 구성된 Copilot API URL에서 Mission Control 기본 URL을 파생합니다. 해당 Mission Control 엔드포인트를 재정의해야 하는 경우에만 설정합니다 `COPILOT_MC_BASE_URL` .

이 작업은 GitHub Enterprise Server 배포에 필요할 수 있습니다. 프로덕션 환경에서 신뢰하기 전에 GitHub 담당자에게 올바른 값 및 지원 상태를 확인합니다.

```shell
COPILOT_MC_BASE_URL="https://example.com/agents"
```

## 클라우드 세션 및 원격 세션

| Capability                   | 원격 세션                  | 클라우드 세션              |
| ---------------------------- | ---------------------- | -------------------- |
| 실행 위치                        | 로컬 컴퓨터 또는 서버           | GitHub 호스팅 컴퓨팅       |
| 미션 컨트롤 역할                    | GitHub 웹/모바일에 로컬 세션 공유 | 호스트된 세션을 만들고 라우팅합니다. |
| SDK 옵션                       |                        |                      |
| `remote: true` 클라이언트 또는 세션에서 |                        |                      |
| `cloud: { ... }` 세션 생성 시     |                        |                      |
| 경로 다시 시작                     | 표준 이력서                 | 표준 이력서               |
| Windows 샌드박스 관련              | 관련이 없는                 | 관련이 없는               |

SDK 런타임이 이미 실행 중인 위치에서 세션이 실행되어야 하지만 Mission Control에서도 액세스할 수 있는 경우 원격 세션을 사용합니다. GitHub 호스팅 컴퓨팅에서 세션을 실행해야 하는 경우 클라우드 세션을 사용합니다.

## Troubleshooting

| 증상                                                                                                  | 가능한 원인                                                                  | 확인할 사항                                                                  |
| --------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| 클라우드 세션 생성이 `"policy_blocked"` 반환됩니다.                                                               | 조직 정책은 클라우드 흐름에서 원격 제어 또는 보기를 차단합니다.                                    | 조직 Copilot 정책 및 사용자 자격 확인                                               |
| 리포지토리 컨텍스트 없이 세션 만들기                                                                                |                                                                         |                                                                         |
| `cloud.repository` 생략되었습니다.                                                                         |                                                                         |                                                                         |
| `owner`, `name` 및 선택적으로 `branch`를 전달하세요                                                             |                                                                         |                                                                         |
| 다시 시작은 새 `cloud` 옵션을 무시합니다.                                                                         |                                                                         |                                                                         |
| `cloud` 새 세션에만 적용됩니다.                                                                               | 기존 세션을 정상적으로 다시 시작합니다.                                                  |                                                                         |
| 샌드박스 설정과 혼동                                                                                         | Windows 샌드박스 및 클라우드 세션은 별개입니다.                                          | 클라우드 실행에는 `SANDBOX=true`를 사용하지 마세요.                                     |
| `session.send`가 `messageId`와 함께 해결되지만 `assistant.*` 이벤트는 전혀 발생하지 않고 Mission Control에도 프롬프트가 표시되지 않음 | session.send가 원격 워커에서 온 `session.start`보다 앞서 실행되었고, 런타임이 프롬프트를 먹어버렸습니다. | 보내기 전에 `session.start`로 첫 번째 `producer === "copilot-agent"` 이벤트를 대기합니다. |
| [첫 번째 프롬프트 보내기](#sending-the-first-prompt) 참조                                                       |                                                                         |                                                                         |
| 클라우드 작업자가 처리 중이더라도 라이브 UI가 업데이트되지 않습니다.                                                             |                                                                         |                                                                         |
| `streaming`에 `createSession`이 설정되지 않았으므로 최종 `assistant.message`만 출력됩니다.                             |                                                                         |                                                                         |
| `streaming: true`에서 `createSession`을(를) 설정하고 다시 시작                                                  |                                                                         |                                                                         |
| 클라우드 세션이 작동하지만 UI에 공유 가능한 URL이 표시되지 않음                                                              | 앱이 URL에 대해 `session.info`를 구독한 적이 없습니다                                  |                                                                         |
| `session.info`를 구독하고 `infoType === "remote"`를 필터링합니다.                                               |                                                                         |                                                                         |
| [Mission Control URL에 액세스하기](#accessing-the-mission-control-url)를 참조하세요                             |                                                                         |                                                                         |

## 참고하십시오

* [원격 세션](/ko/copilot/how-tos/copilot-sdk/features/remote-sessions): Mission Control을 통해 로컬로 호스트되는 세션 공유
* [스트리밍 세션 이벤트](/ko/copilot/how-tos/copilot-sdk/features/streaming-events): 실시간 UI 렌더링용 `assistant.*` 델타 구독
* [다중 테넌트 및 서버 배포](/ko/copilot/how-tos/copilot-sdk/setup/multi-tenancy): 통합 ID 및 서버 배포 패턴
* [인증](/ko/copilot/how-tos/copilot-sdk/auth): SDK 세션에 대한 GitHub 인증 구성