Skip to main content
Skip to content

세션 다시 시작 및 지속성

이 가이드에서는 SDK의 세션 지속성 기능(작업을 일시 중지하고, 나중에 다시 시작하고, 프로덕션 환경에서 세션을 관리하는 방법)을 안내합니다.

세션 작동 방식

세션을 만들 때 Copilot CLI는 대화 기록, 도구 상태 및 계획 컨텍스트를 유지 관리합니다. 기본적으로 이 상태는 메모리에 있으며 세션이 종료되면 사라집니다. 지속성을 사용하도록 설정하면 다시 시작, 컨테이너 마이그레이션 또는 다른 클라이언트 인스턴스 간에 세션을 다시 시작할 수 있습니다.

다이어그램: 설명된 프로세스를 보여 주는 순서도입니다.

상태어떻게 되나요?
창조하다session_id 할당
Active프롬프트 보내기, 도구 호출, 응답
일시 중지된디스크에 저장된 상태
다시 시작디스크에서 로드된 상태

빠른 시작: 다시 시작 가능한 세션 만들기

재개 가능한 세션의 핵심은 자체 session_id를 제공하는 것입니다. 이 ID가 없으면 SDK는 임의 ID를 생성하고 세션은 나중에 다시 시작될 수 없습니다.

TypeScript

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

const client = new CopilotClient();

// Create a session with a meaningful ID
const session = await client.createSession({
  sessionId: "user-123-task-456",
  model: "gpt-5.2-codex",
});

// Do some work...
await session.sendAndWait({ prompt: "Analyze my codebase" });

// Session state is automatically persisted
// You can safely close the client

Python

from copilot import CopilotClient
from copilot.session import PermissionHandler

client = CopilotClient()
await client.start()

# Create a session with a meaningful ID
session = await client.create_session(on_permission_request=PermissionHandler.approve_all, model="gpt-5.2-codex", session_id="user-123-task-456")

# Do some work...
await session.send_and_wait("Analyze my codebase")

# Session state is automatically persisted

Go

ctx := context.Background()
client := copilot.NewClient(nil)

// Create a session with a meaningful ID
session, _ := client.CreateSession(ctx, &copilot.SessionConfig{
    SessionID: "user-123-task-456",
    Model:     "gpt-5.2-codex",
})

// Do some work...
session.SendAndWait(ctx, copilot.MessageOptions{Prompt: "Analyze my codebase"})

// Session state is automatically persisted

C#(.NET)

using GitHub.Copilot;

var client = new CopilotClient();

// Create a session with a meaningful ID
var session = await client.CreateSessionAsync(new SessionConfig
{
    SessionId = "user-123-task-456",
    Model = "gpt-5.2-codex",
});

// Do some work...
await session.SendAndWaitAsync(new MessageOptions { Prompt = "Analyze my codebase" });

// Session state is automatically persisted

세션 다시 열기

나중에(분, 시간 또는 며칠) 중단된 위치에서 세션을 다시 시작할 수 있습니다.

세션 파일 시스템에 저장된 권한

사용자 지정 sessionFs 공급자를 구성할 때 런타임 소유의 영구 권한 옵션은 런타임 호스트의 구성 대신 공급자 스토리지를 사용합니다. 파일은 공급자의 sessionStatePath 아래에 위치하며 기존 형식을 유지합니다.

  • permissions.json: 기존 allowed_directories 및 locations 필드를 유지하는 최상위 tool_approvals 맵
  • settings.json: allowedUrls URL 승인에 대한 최상위 수준 sandbox 및 저장된 샌드박스 기본 설정에 대한 approve-permanently
  • config.json: 기억된 폴더 신뢰에 대한 최상위 수준 sandboxOnboardingShown 및 처음 활성화 시 샌드박스 메시지에 대한 trustedFolders

위치 키는 /workspace와 같은 정규화된 공급자 디렉터리 경로이며, 접두사는 추가되지 않습니다. 런타임은 호스트 파일 시스템을 검사하거나 호스트 Git 리포지토리를 검색하지 않고 공급자 경로 규칙을 사용하여 이를 렉시컬 방식으로 해석합니다. /workspace/sub에 대해 저장된 승인은 작업 디렉터리가 /workspace인 경우 자동으로 선택되지 않습니다.

공급자 기반 폴더 트러스트도 문자열 기준 경로를 사용합니다. 신뢰할 수 있는 폴더는 다른 경로에 연결된 Git 작업 트리가 아니라 폴더 자체와 그 하위 항목에 적용됩니다. 해당 작업 트리 경로를 명시적으로 신뢰하십시오.

이러한 파일 내에는 추가 세션 ID 파티션이 없습니다. 동일한 기반 파일에 액세스하는 세션은 기억된 선택 항목을 공유합니다. 세션 또는 테넌트가 권한 부여를 공유해서는 안 될 경우 별도의 공급자 네임스페이스를 사용합니다. 세션당 네임스페이스를 사용하면 영구 선택 항목이 해당 세션을 재개 시에도 유지되지만 새 세션으로 자동 전달되지는 않습니다. 다시 시작할 때 세션의 지속형 선택 항목을 복원하려면 동일한 네임스페이스에 다시 연결하세요.

동의 업데이트는 하나의 런타임 프로세스 내에서 공급자 엔드포인트 및 파일별로 직렬화됩니다. 별도의 엔드포인트는 서로를 차단하지 않습니다. 다른 공급자 엔드포인트 또는 런타임 프로세스가 기반 파일을 공유하는 경우 애플리케이션은 동시 업데이트를 조정해야 합니다. 런타임은 해당 파일이 공유되는 것을 유추할 수 없습니다.

이러한 작업은 공급자 읽기 또는 쓰기가 실패하는 경우를 포함하여 호스트의 permissions-config.json, settings.json 또는 config.json를 가져오거나, 업데이트하거나, 대신 사용하지 않습니다. 공급자를 통해 제공된 기존 형식 파일은 직접 읽습니다.

호스트 구성과 마찬가지로 URL 승인은 settings.json에서만 읽기 전용입니다. 레거시 allowedUrls 필드는 config.json에서는 무시됩니다. config.json는 저장된 폴더 신뢰 설정 및 샌드박스 온보딩 표식에 대한 전역 상태 파일로 유지됩니다.

스토리지 라우팅은 사용 권한 수명, URL 거부 우선 순위 또는 세션 정책 동작을 변경하지 않습니다. ‘한 번 승인’ 및 ‘세션 동안 승인’은 영구 부여가 되지 않습니다.

저장된 샌드박스 기본 설정은 만들기 및 재개 시 복원됩니다. 나중에 명시적 SDK options.update 호출은 저장된 기본 설정을 덮어쓰지 않고 라이브 샌드박스 구성을 변경할 수 있습니다.

sessionFs 없이 SDK 애플리케이션은 copilot-cli 및 empty 모드 모두에서 기존 호스트 지원 지속성을 유지합니다. 여기에는 영구 URL 동의가 호스트 설정을 저장하고 라이브 세션에서 액세스 권한을 부여하지만 새 SDK 세션이 호스트 URL 허용 목록을 자동으로 로드하지 않는 기존 동작이 포함됩니다.

다중 테넌트 및 서버 배포에서 공급자 격리 책임을 참조하세요.

대화 기록 복구

재개 옵션은 allowTranscriptRecovery 런타임이 스토리지에서 기록을 로드할 때 복구를 제어합니다. 기본값은 모든 모드에서 true로 설정됩니다. false 사용 시 손상된 레코드를 삭제하거나 session.start을 이동하려는 로드는 기록을 다시 작성하지 않고 JSON-RPC 오류 -32075와 함께 실패합니다. 개행 문자 없이 온전한 최종 레코드가 허용됩니다.

정방향 호환성을 위해 건너뛴 레코드는 영속된 순서를 확인할 때도 계속 계산됩니다. 이러한 레코드가 session.start보다 앞에 오는 경우 복구는 시작 레코드를 그들 앞으로 이동해야 합니다. 건너뛴 레코드만 포함하는 기록은 비어 있지 않으며 유효한 session.start 없이는 복구할 수 없습니다.

복구가 허용되면 반환된 세션은 session.start를 제공하며, 여기에는 잘못된 줄 번호, transcriptRecovery의 이동 여부 및 계획된 바이트 정확한 백업 경로가 포함됩니다. 로드만으로는 해당 백업이 작성되지 않습니다. 다음 내구성 있는 추가 기록이 수리 및 백업을 수행합니다.

참고

이 옵션은 세션의 수명이 아닌 새 전사록 로드에 적용됩니다. 런타임에 이미 상주하는 세션에 다시 연결하면 스토리지를 다시 검증하거나 이전 재개에서 승인된 복구를 거부하지 않고 라이브 기록이 재사용됩니다. 복구 보고서는 모든 후속 재연결이 아니라 복구를 수행한 로드를 설명합니다.

다이어그램: 설명된 프로세스를 보여 주는 순서도입니다.

TypeScript

// Resume from a different client instance (or after restart)
const session = await client.resumeSession("user-123-task-456");

// Continue where you left off
await session.sendAndWait({ prompt: "What did we discuss earlier?" });

Python

# Resume from a different client instance (or after restart)
session = await client.resume_session("user-123-task-456", on_permission_request=PermissionHandler.approve_all)

# Continue where you left off
await session.send_and_wait("What did we discuss earlier?")

Go

ctx := context.Background()

// Resume from a different client instance (or after restart)
session, _ := client.ResumeSession(ctx, "user-123-task-456", nil)

// Continue where you left off
session.SendAndWait(ctx, copilot.MessageOptions{Prompt: "What did we discuss earlier?"})

C#(.NET)

// Resume from a different client instance (or after restart)
var session = await client.ResumeSessionAsync("user-123-task-456");

// Continue where you left off
await session.SendAndWaitAsync(new MessageOptions { Prompt = "What did we discuss earlier?" });

다시 시작 옵션

세션을 다시 시작하면 필요에 따라 여러 설정을 다시 구성할 수 있습니다. 이 기능은 모델을 변경하거나, 도구 구성을 업데이트하거나, 동작을 수정해야 하는 경우에 유용합니다.

OptionDescription
model다시 시작된 세션의 모델 변경
systemMessage시스템 프롬프트 재정의 또는 확장
availableTools사용할 수 있는 도구 제한
excludedTools특정 도구 사용 안 함
providerBYOK 자격 증명 다시 제공(BYOK 세션에 필요)
capi.autoTier저장된 자동 라우팅 기본 설정을 재정의
capi.enableWebSocketResponses다시 시작된 세션에 대한 응답 API 전송 선택
reasoningEffort추론 노력 수준 조정
streaming스트리밍 응답 사용/사용 안 함
workingDirectory작업 디렉터리 변경
configDir구성 디렉터리를 재정의
mcpServersMCP 서버 구성
customAgents사용자 지정 에이전트 구성
agent이름으로 사용자 지정 에이전트 사전 선택
skillDirectories기술을 로드하기 위한 디렉터리
disabledSkills사용하지 않도록 설정하는 기술
infiniteSessions무한 세션 동작 구성

자동 계층 유지

를 model: "auto"사용하면 선택적 capi.autoTier 설정에서 자동 라우팅 기본 설정인 efficiency, balance, intelligence또는 fast.를 선택합니다. Python에서는 capi={"auto_tier": "balance"}를 사용하세요. 이 설정은 V2 자동 라우팅에 적용됩니다. V1 자동 요청은 변경되지 않습니다.

런타임의 기본 해제 DYNAMIC_AUTO_TIERS 기능을 사용하도록 설정하면 세션의 model.list RPC도 공급자의 auto 엔드포인트에서 선택적 /meta 메타데이터를 반환합니다. type: "auto"와 함께 활성화된 설명자를 사용하여 지원되는 추가 계층 식별자, 표시 이름, 설명 및 순서를 검색합니다. 기존 선택 메서드 및 JSON 필드는 이러한 식별자를 허용합니다. 검색 실패는 /models로 대체되지 않으며 메타데이터가 없는 성공적인 auto 응답은 선택 가능한 자동 계층을 제공하지 않습니다.

세션이 아직 존재하지 않기 전에 모델 선택기를 채우려면 런타임의 환경에서 env을(를) 사용하도록 설정하세요(예: DYNAMIC_AUTO_TIERS 클라이언트 옵션). 그런 다음 서버 수준 models.list RPC(client.rpc.models.list() Node.js)는 동일한 /meta 응답에서 동일한 auto 메타데이터를 동일한 폴백 없음 동작으로 반환합니다. 서버 수준 목록은 세션별 기능 플래그나 실험 할당이 아니라 시작 시 런타임이 확인한 플래그를 표시하므로, 런타임을 시작할 때 해당 플래그를 설정하세요. 플래그를 비활성화하면 models.list는 변경되지 않으며 auto를 생략합니다.

계층 식별자를 폐쇄형 열거형이 아닌 확장 가능한 값으로 처리합니다. 기존 명명된 값은 계속 사용할 수 있습니다. 추가 식별자의 경우 Node.js 및 Python에서는 문자열을, Go에서는 AutoTier("premium-v2"), .NET에서는 new AutoTier("premium-v2"), Rust에서는 AutoTier::Custom, Java에서는 AutoTier.fromValue를 사용합니다. 공급자의 defaultTier는 커밋된 SDK 기본 설정을 만들지 않고 기본 라우팅을 설명합니다.

지속형 계층을 제거하거나 사용하지 않도록 설정한 경우 resume는 공급자의 기본값으로 바꾸는 대신 명시적 기본 설정을 유지합니다. 자동 라우팅을 활성화하기 전에 사용 가능한 대체 항목을 선택합니다.

또한 CLI는 계층을 사용할 수 없거나 동적 검색을 사용하지 않도록 설정한 경우에도 시작 중에 설정 파생 기본 설정을 유지합니다. 그런 다음 모델 선택 메뉴에서 대체 모델을 선택할 수 있습니다. 명시적 SDK 생성 및 재개 기본 설정은 작업이 성공하기 전에 여전히 유효성을 검사하며 자동 활성화는 항상 확정된 검색 모드에 대해 가용성을 검증합니다.

만들기 또는 다시 시작 요청에 expAssignments이 포함된 경우 런타임은 명시적 자동 기본 설정의 유효성을 검사하기 전에 해당 할당을 설치합니다. 유효성 검사, 검색 및 활성화는 동일한 해결된 기능 결정을 사용합니다.

fast는 자사 GitHub Copilot 제품 기본 설정이 아닌 통합자 전용 대기 시간 사전 설정입니다. 세션을 구성할 때 Fast는 /meta 계층 카탈로그를 기준으로 유효성이 검사되지 않습니다. SDK는 빠른 자격을 결정하거나, 클라이언트 ID를 검사하거나, 기본값으로 선택하거나, 런타임이 지원하지 않을 때 다른 계층으로 대체하지 않습니다. 이전 런타임은 기본 오류를 변경하지 않고 반환합니다.

런타임은 선택한 계층을 유지하므로 애플리케이션은 모든 다시 시작 시 다시 보내지 않아도 됩니다.

  • 세션을 만들 때 계층을 생략하면 런타임의 기본 라우팅 동작이 사용됩니다.
  • 콜드 재개는 지속형 계층을 복원합니다. 계층을 명시적으로 지정하면 새 활성화 시 복원된 값보다 우선 적용됩니다.
  • 런타임에 이미 상주 중인 세션을 재개할 때 계층을 생략하면 현재 선택 상태가 유지되며, 동일한 계층을 지정해도 아무 동작도 하지 않습니다. 다른 계층을 지정하면 재개가 성공한 후 런타임이 적용하는 안전한 전환을 요청하게 되며, 이미 진행 중인 턴은 변경할 수 없습니다.
  • 지속형 계층이 없는 이전 세션은 기본 라우팅 동작을 유지합니다.

계층 선택은 라이브 모델 전환 작업이 아닙니다. SDK는 기본 설정을 전달합니다. 런타임은 지속성 및 유효성 검사를 소유합니다.

session.start 및 session.resume 이벤트는 선택한 계층을 선택적 data.autoTier 필드(data.auto_tierPython)에 노출합니다. 계층을 선택하지 않으면 필드가 생략됩니다.

세션 중 자동 계층 변경

선택한 모델을 변경하지 않고 라이브 세션에서 라우팅 기본 설정을 변경하려면 호출 setAutoTier 합니다. 공급자의 기본 Auto 라우팅으로 돌아가려면 null (Python None, Go nil)를 전달하세요.

const result = await session.setAutoTier("intelligence");
if (result.status === "pending") {
  // Accepted, but not yet in effect.
}

런타임은 기본 설정을 즉시 적용하지 않습니다. 요청을 기록하고, 이후 auto 모델을 사용하는 사용자 턴에서 공급자로부터 사용 가능한 모델을 성공적으로 얻은 경우에만 이를 커밋합니다. pending 따라서 상태는 요청이 적용되지 않고 수락되었음을 확인합니다. 가장 최근의 요청만 유지됩니다. 새 요청은 아직 요청하지 않은 이전 요청을 대체합니다.

최신 기본 설정 요청 또는 재설정이 도착할 때 이전 요청이 여전히 검증 중인 경우 이전 호출은 최신 의도를 바꾸는 대신 후속 요청으로 대체됨 오류로 실패합니다.

다음 이벤트를 통해 결과를 확인합니다.

  • session.model_change 기본 설정이 커밋되면
  •           그렇지 않은 경우 `session.auto_tier_switch_failed`. 이 이벤트는 임시 이벤트이므로 런타임은 다시 시작할 때 지속되거나 재생되지 않습니다. 해당 `reason` 필드는 , `request_failed``setup_failed`또는 `unsupported`그 중 하나이며 `policy_rejected`이전에 유효했던 기본 설정은 활성 상태로 유지됩니다.
    

또한 세션의 model.getCurrent RPC 메서드를 통해 언제든지 권한 있는 상태를 읽을 수 있으며, 이 메서드는 커밋된 autoTier, 아직 클레임되지 않은 pendingAutoTier, 그리고 진행 중인 활성화에 의해 현재 클레임된 activatingAutoTier를 보고합니다.

SDK계층 변경공급자 기본 라우팅으로 돌아가기
Node.JSsession.setAutoTier("balance")session.setAutoTier(null)
Pythonsession.set_auto_tier("balance")session.set_auto_tier(None)
Gosession.SetAutoTier(ctx, &tier)session.SetAutoTier(ctx, nil)
.NETsession.SetAutoTierAsync(AutoTier.Balance)session.SetAutoTierAsync(null)
러스트session.set_auto_tier(Some(AutoTier::Balance))session.set_auto_tier(None)
Javasession.setAutoTier(AutoTier.BALANCE)session.setAutoTier(null)

단일 호출에서 auto 모델과 해당 라우팅 기본 설정을 선택하려면, 대신 모델 스위치에서 티어를 설정하세요. 모델이 auto가 아닌 경우 런타임은 이 옵션을 거부합니다.

SDK스위치로 티어를 스테이징합니다공급자 기본 라우팅으로 다시 설정
Node.JSsetModel("auto", { autoTier: "balance" })setModel("auto", { autoTier: null })
Pythonset_model("auto", auto_tier="balance")set_model("auto", auto_tier=None)
GoSetModelOptions{AutoTier: &tier}SetModelOptions{ResetAutoTier: true}
.NETnew SetModelOptions { AutoTier = AutoTier.Balance }new SetModelOptions { ResetAutoTier = true }
러스트SetModelOptions::default().with_auto_tier(AutoTier::Balance)SetModelOptions::default().with_reset_auto_tier()
Javanew SetModelOptions().setModel("auto").setAutoTier(AutoTier.BALANCE)new SetModelOptions().setModel("auto").setResetAutoTier(true)

Node.js, Python 및 Rust는 생략된 인수와 구별할 수 있으므로 Node.js 및 Pythonnull/None, Rust AutoTierPreference::Reset 는 동일한 옵션의 고유한 변형이므로 세 가지 상태를 모두 단일 값으로 표현합니다. Go, .NET 및 Java "reset"과 "unset"을 한 값으로 구분할 방법이 없으므로 별도의 재설정 플래그를 전달합니다. 둘 다 생략한다는 것은 항상 "현재 기본 설정을 혼자 두는 것"을 의미합니다.

다시 시작할 때 응답 전송

선택적 capi.enableWebSocketResponses 설정은 CAPI 응답 API에 대한 전송을 선택합니다. 기본값은 true로 설정되어 있으므로, 선택한 모델이 ws:/responses 엔드포인트를 지원한다고 알리는 경우에는 항상 WebSocket 전송이 사용됩니다. false로 설정하면 HTTP 전송으로 폴백됩니다. Python에서는 capi={"enable_web_socket_responses": False}를 사용하세요.

필요한 경우 재개 호출 시 이를 제공하세요. WebSocket 연결이 프록시 환경에서 실패하거나, 재개된 세션에서 WebSocket 전송에만 해당하는 400 input item ID does not belong to this connection가 보고될 때 이 설정을 사용하는 것이 좋습니다.

const session = await client.resumeSession("user-123-task-456", {
  capi: { enableWebSocketResponses: false },
});

이 값을 false 설정하는 것은 반대 극성을 가진 환경 변수와 동일합니다 COPILOT_CLI_DISABLE_WEBSOCKET_RESPONSES .

예: 다시 시작할 때 모델 변경

// Resume with a different model
const session = await client.resumeSession("user-123-task-456", {
  model: "claude-sonnet-4",  // Switch to a different model
  reasoningEffort: "high",   // Increase reasoning effort
});

다시 시작된 세션과 함께 BYOK(사용자 고유의 키 가져오기) 사용

사용자 고유의 API 키를 사용하는 경우 다시 시작 시 공급자 구성을 다시 제공해야 합니다. API 키는 보안상의 이유로 디스크에 유지되지 않습니다.

// Original session with BYOK
const session = await client.createSession({
  sessionId: "user-123-task-456",
  model: "gpt-5.2-codex",
  provider: {
    type: "azure",
    endpoint: "https://my-resource.openai.azure.com",
    apiKey: process.env.AZURE_OPENAI_KEY,
    deploymentId: "my-gpt-deployment",
  },
});

// When resuming, you MUST re-provide the provider config
const resumed = await client.resumeSession("user-123-task-456", {
  provider: {
    type: "azure",
    endpoint: "https://my-resource.openai.azure.com",
    apiKey: process.env.AZURE_OPENAI_KEY,  // Required again
    deploymentId: "my-gpt-deployment",
  },
});

지속되는 항목은?

세션 상태는 다음으로 저장됩니다 ~/.copilot/session-state/{sessionId}/.

~/.copilot/session-state/
└── user-123-task-456/
    ├── checkpoints/           # Conversation history snapshots
    │   ├── 001.json          # Initial state
    │   ├── 002.json          # After first interaction
    │   └── ...               # Incremental checkpoints
    ├── plan.md               # Agent's planning state (if any)
    └── files/                # Session artifacts
        ├── analysis.md       # Files the agent created
        └── notes.txt         # Working documents
데이터보존되었습니까?비고
대화 기록
✅ 예전체 메시지 스레드
도구 호출 결과
✅ 예컨텍스트용으로 캐시됨
에이전트 계획 상태
✅ 예
plan.md 파일
세션 아티팩트
✅ 예
files/ 디렉터리 안에
공급자/API 키
❌ 아니요보안: 다시 제공해야 합니다.
메모리 내 도구 상태
❌ 아니요도구는 무상태여야 합니다.

세션 ID 모범 사례

소유권 및 용도를 인코딩하는 세션 ID를 선택합니다. 이렇게 하면 감사 및 정리가 훨씬 쉬워집니다.

PatternExample사용 사례
❌abc123임의 ID감사하기 어렵고 소유권 정보 없음
✅user-{userId}-{taskId}user-alice-pr-review-42다중 사용자 앱
✅tenant-{tenantId}-{workflow}tenant-acme-onboarding다중 사용자 SaaS
✅{userId}-{taskId}-{timestamp}alice-deploy-1706932800시간 기반 정리 작업

구조적 ID의 이점:

  • 감사가 용이합니다: "사용자 alice의 모든 세션 표시"
  • 정리하기 쉽습니다. "X보다 오래된 모든 세션 삭제"
  • 자연 액세스 제어: 세션 ID에서 사용자 ID 추출

예: 세션 ID 생성

function createSessionId(userId: string, taskType: string): string {
  const timestamp = Date.now();
  return `${userId}-${taskType}-${timestamp}`;
}

const sessionId = createSessionId("alice", "code-review");
// → "alice-code-review-1706932800000"
import time

def create_session_id(user_id: str, task_type: str) -> str:
    timestamp = int(time.time())
    return f"{user_id}-{task_type}-{timestamp}"

session_id = create_session_id("alice", "code-review")
# → "alice-code-review-1706932800"

세션 수명 주기 관리

활성 세션 나열

// List all sessions
const sessions = await client.listSessions();
console.log(`Found ${sessions.length} sessions`);

for (const session of sessions) {
  console.log(`- ${session.sessionId} (created: ${session.createdAt})`);
}

// Filter sessions by repository
const repoSessions = await client.listSessions({ repository: "owner/repo" });

이전 세션 정리

async function cleanupExpiredSessions(maxAgeMs: number) {
  const sessions = await client.listSessions();
  const now = Date.now();
  
  for (const session of sessions) {
    const age = now - new Date(session.createdAt).getTime();
    if (age > maxAgeMs) {
      await client.deleteSession(session.sessionId);
      console.log(`Deleted expired session: ${session.sessionId}`);
    }
  }
}

// Clean up sessions older than 24 hours
await cleanupExpiredSessions(24 * 60 * 60 * 1000);

세션에서 연결 끊기(disconnect)

작업이 완료되면 시간 제한을 기다리지 않고 세션에서 명시적으로 연결을 끊습니다. 이렇게 하면 메모리 내 리소스가 해제되지만 디스크에 세션 데이터가 유지되므로 나중에 세션을 다시 시작해도 됩니다.

try {
  // Do work...
  await session.sendAndWait({ prompt: "Complete the task" });
  
  // Task complete — release in-memory resources (session can be resumed later)
  await session.disconnect();
} catch (error) {
  // Clean up even on error
  await session.disconnect();
  throw error;
}

또한 각 SDK는 해당 언어에 맞는 자동 정리 패턴도 제공합니다:

언어PatternExample
TypeScriptSymbol.asyncDisposeawait using session = await client.createSession(config);
Pythonasync with 컨텍스트 관리자async with await client.create_session(on_permission_request=handler) as session:
C#IAsyncDisposableawait using var session = await client.CreateSessionAsync(config);
Godeferdefer session.Disconnect()

참고

destroy()은 더 이상 사용되지 않으며, 대신 disconnect() 사용이 권장됩니다. 사용하는 destroy() 기존 코드는 계속 작동하지만 마이그레이션해야 합니다.

세션 영구 삭제(deleteSession)

디스크에서 세션과 그 모든 데이터(대화 기록, 계획 상태, 아티팩트)를 영구적으로 제거하려면 deleteSession를 사용하십시오. 이는 되돌릴 수 없습니다. 삭제 후 세션을 다시 시작 하지 못할 수 있습니다 .

// Permanently remove session data
await client.deleteSession("user-123-task-456");

disconnect() vs deleteSession():disconnect() 메모리 내 리소스를 해제하지만 나중에 다시 시작하려면 세션 데이터를 디스크에 유지합니다. deleteSession() 는 디스크의 파일을 포함하여 모든 항목을 영구적으로 제거합니다.

자동 정리: 유휴 시간 제한

기본적으로 세션은 유휴 시간 제한이 없으며 명시적으로 연결이 끊어지거나 삭제될 때까지 무기한으로 라이브됩니다. 필요에 따라 다음을 통해 CopilotClientOptions.sessionIdleTimeoutSeconds서버 전체 유휴 시간 제한을 구성할 수 있습니다.

const client = new CopilotClient({
  sessionIdleTimeoutSeconds: 30 * 60, // 30 minutes
});

시간 제한이 구성되면 해당 기간 동안 활동이 없는 세션이 자동으로 정리됩니다. 비활성화하려면 0로 설정하거나 생략합니다.

참고

이 옵션은 SDK가 런타임 프로세스를 생성하는 경우에만 적용됩니다. 를 통해 cliUrl기존 서버에 연결할 때 서버의 자체 시간 제한 구성이 적용됩니다.

다이어그램: 설명된 프로세스를 보여 주는 순서도입니다.

활성 작업(실행 중인 명령, 백그라운드 에이전트)이 있는 세션은 제한 시간 설정에 관계없이 항상 유휴 정리로부터 보호됩니다.

유휴 이벤트를 수신 대기하여 세션 비활성 상태에 반응합니다.

session.on("session.idle", (event) => {
  console.log(`Session idle for ${event.idleDurationMs}ms`);
});

배포 패턴

적합 대상: 강력한 격리, 다중 테넌트 환경, Azure 동적 세션.

다이어그램: 설명된 프로세스를 보여 주는 순서도입니다.

**혜택:**✅ 완전한 격리 | ✅ 단순 보안 | ✅ 간편한 크기 조정

패턴 2: 공유 CLI 서버(리소스 효율적)

적합 대상: 내부 도구, 신뢰할 수 있는 환경, 리소스 제한 설정.

다이어그램: 설명된 프로세스를 보여 주는 순서도입니다.

Requirements:

  • ⚠️ 사용자당 고유한 세션 ID
  • ⚠️ 애플리케이션 수준 액세스 제어
  • ⚠️ 작업 전 세션 ID 유효성 검사
// Application-level access control for shared CLI
async function resumeSessionWithAuth(
  client: CopilotClient,
  sessionId: string,
  currentUserId: string
): Promise<Session> {
  // Parse user from session ID
  const [sessionUserId] = sessionId.split("-");
  
  if (sessionUserId !== currentUserId) {
    throw new Error("Access denied: session belongs to another user");
  }
  
  return client.resumeSession(sessionId);
}

Azure 동적 세션

컨테이너를 다시 시작하거나 마이그레이션할 수 있는 서버리스/컨테이너 배포의 경우:

영구 스토리지 탑재

세션 상태 디렉터리를 영구 스토리지에 탑재해야 합니다.

# Azure Container Instance example
containers:
  - name: copilot-agent
    image: my-agent:latest
    volumeMounts:
      - name: session-storage
        mountPath: /home/app/.copilot/session-state

volumes:
  - name: session-storage
    azureFile:
      shareName: copilot-sessions
      storageAccountName: myaccount

다이어그램: 설명된 프로세스를 보여 주는 순서도입니다.

컨테이너를 다시 시작해도 세션이 유지됩니다!

장기 실행 워크플로를 위한 무한 세션

컨텍스트 제한을 초과할 수 있는 워크플로의 경우 자동 압축을 사용하여 무한 세션을 사용하도록 설정합니다.

const session = await client.createSession({
  sessionId: "long-workflow-123",
  infiniteSessions: {
    enabled: true,
    backgroundCompactionThreshold: 0.80,  // Start compaction at 80% context
    bufferExhaustionThreshold: 0.95,      // Block at 95% if needed
  },
});

참고

임계값은 절대 토큰 수가 아닌 컨텍스트 사용률(0.0-1.0)입니다. 자세한 내용은 SDK 및 CLI 호환성 을 참조하세요.

제한 사항 및 고려 사항

LimitationDescription완화 방법
BYOK 다시 인증API 키는 유지되지 않습니다.비밀 관리자에 키를 저장합니다. 이력서에 제공
쓰기 가능한 스토리지~/.copilot/session-state/ 쓰기 가능해야 합니다.컨테이너에 영구 볼륨 탑재
세션 잠금 없음동일한 세션에 대한 동시 액세스가 정의되지 않았습니다.애플리케이션 레벨 잠금 또는 큐 시스템 구현
도구 상태가 유지되지 않음메모리 내 도구 상태가 손실됨상태 비저장이 되거나, 자체 상태를 유지하도록 도구를 설계하세요.

동시 액세스 처리

SDK는 기본 제공 세션 잠금을 제공하지 않습니다. 여러 클라이언트가 동일한 세션에 액세스할 수 있는 경우:

// Option 1: Application-level locking with Redis
import Redis from "ioredis";

const redis = new Redis();

async function withSessionLock<T>(
  sessionId: string,
  fn: () => Promise<T>
): Promise<T> {
  const lockKey = `session-lock:${sessionId}`;
  const acquired = await redis.set(lockKey, "locked", "NX", "EX", 300);
  
  if (!acquired) {
    throw new Error("Session is in use by another client");
  }
  
  try {
    return await fn();
  } finally {
    await redis.del(lockKey);
  }
}

// Usage
await withSessionLock("user-123-task-456", async () => {
  const session = await client.resumeSession("user-123-task-456");
  await session.sendAndWait({ prompt: "Continue the task" });
});

요약

특징사용 방법
다시 열 수 있는 세션 만들기사용자 고유의 것을 제공하십시오 sessionId
세션 다시 시작client.resumeSession(sessionId)
BYOK 다시 시작provider 구성 다시 제공
세션 목록client.listSessions(filter?)
활성 세션에서 연결 끊기session.disconnect()- 메모리 내 리소스를 해제합니다. 디스크의 세션 데이터는 재개를 위해 유지됩니다.
세션을 영구적으로 삭제client.deleteSession(sessionId)- 디스크에서 모든 세션 데이터를 영구적으로 제거합니다. 을(를) 다시 시작하지 못 함
컨테이너화된 배포영구 스토리지에 탑재 ~/.copilot/session-state/

다음 단계