Skip to main content

클라우드 세션

로컬 CLI 세션 대신 Mission Control을 통해 GitHub 호스팅 컴퓨팅에서 Copilot 세션을 실행합니다.

사전 요구 사항

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

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

클라우드 세션 만들기

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

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

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",
        )
    ),
)

이동

package main

import (
    "context"

    copilot "github.com/github/copilot-sdk/go"
    "github.com/github/copilot-sdk/go/rpc"
)

func main() {
    _ = run(context.Background())
}

func run(ctx context.Context) error {
    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(_ copilot.PermissionRequest, _ copilot.PermissionInvocation) (rpc.PermissionDecision, error) {
            return &rpc.PermissionDecisionApproveOnce{}, nil
        },
    })
    _ = session
    return err
}
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

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

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();
}

러스트

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?;

첫 번째 프롬프트 보내기

클라우드 세션은 두 단계로 초기화됩니다: 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" 이벤트를 기다립니다.

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" });

몇 가지 참고 사항:

  • 런타임이 assistant.message_delta 이벤트를 내보내도록 createSession에서 streaming: true을 설정합니다. 이 신호가 없으면 받을 수 있는 어시스턴트 신호는 마지막 assistant.message뿐입니다. 배치 처리에는 괜찮지만, 실시간 UI를 렌더링하고 있다면 채팅이 멈춘 것처럼 보일 것입니다. 스트리밍 세션 이벤트을(를) 참조하세요.
  • 오직 첫 번째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"으로 필터링하세요:

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

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

remote: true를 통해 승격된 로컬 세션의 동일한 배선에 대해서는 원격 세션을 참조하세요.

리포지토리 연결

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

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

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

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

클라우드 세션 다시 열기

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

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

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

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

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

조직 정책 및 자격

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

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

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

import {
  CopilotClient,
  type CloudSessionRepository,
} from "@github/copilot-sdk";

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

const repository: CloudSessionRepository = {
  owner: "github",
  name: "copilot-sdk",
};

try {
  await client.createSession({
    cloud: { repository },
    onPermissionRequest: async () => ({ kind: "approve-once" }),
  });
} catch (error) {
  if ((error as { reason?: string }).reason === "policy_blocked") {
    // Show an admin-facing message or link to org policy settings.
  }
  throw error;
}
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 세부 정보는 다중 테넌트 및 서버 배포을 참조하세요.

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 담당자에게 올바른 값 및 지원 상태를 확인합니다.

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.sendmessageId와 함께 해결되지만 assistant.* 이벤트는 전혀 발생하지 않고 Mission Control에도 프롬프트가 표시되지 않음session.send가 원격 워커에서 온 session.start보다 앞서 실행되었고, 런타임이 프롬프트를 먹어버렸습니다.보내기 전에 producer === "copilot-agent"로 첫 번째 session.start 이벤트를 대기합니다.
첫 번째 프롬프트 보내기 참조
클라우드 작업자가 처리 중이더라도 라이브 UI가 업데이트되지 않습니다.
createSessionstreaming이 설정되지 않았으므로 최종 assistant.message만 출력됩니다.
createSession에서 streaming: true을(를) 설정하고 다시 시작
클라우드 세션이 작동하지만 UI에 공유 가능한 URL이 표시되지 않음앱이 URL에 대해 session.info를 구독한 적이 없습니다
session.info를 구독하고 infoType === "remote"를 필터링합니다.
Mission Control URL에 액세스하기를 참조하세요

참고하십시오