Skip to main content

云会话

通过任务控制而不是本地 CLI 会话,在GitHub托管的计算上运行Copilot会话。

先决条件

在创建云会话之前,请确保:

  • 用户拥有 Copilot 访问权限,并享有云代理使用权益。
  • 会话可以使用用户令牌,也可以使用已登录的 Copilot CLI 身份向 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",
        )
    ),
)

Go

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

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

发送第一个提示词

云会话分两个阶段完成初始化:任务管控中心预留任务资源后,createSession 即完成解析,但远程 copilot-agent 工作进程还需耗时一两秒建立连接并发出 session.start。 若在此之前调用 session.send,运行时 RemoteSession.send 会抛出 "Remote session is still starting";不过架构封装层采用即发即弃机制,会静默捕获异常,同时仍向代码返回全新的 messageId 实例。 提示在服务器端被丢弃,永远不会到达工作进程。

为了确保可靠发送,请在发送前订阅事件,并等待第一个 producer"copilot-agent"session.start 事件:

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

一些说明:

  • createSession 上设置 streaming: true,从而使运行时发出 assistant.message_delta 事件。 如果没有它,你获得的唯一助手信号是最终 assistant.message 信号 -- 适合批量使用,但如果呈现实时 UI,聊天会呈现卡死状态。 请参阅“流式处理会话事件”。
  • 首次session.send调用会受此竞态问题影响。 在同一会话中的后续发送都会正常进行,因为运行时会使 hasSessionStarted 在整个会话期间保持已设置状态。
  • ready Promise 配置超时(例如 60 秒),防止任务管控中心资源配置卡死造成你的应用永久阻塞。
  • 同一模式适用于每个 SDK 语言 - 订阅 session.start、检查 producer === "copilot-agent"、然后调用 send

访问 Mission Control 的 URL

云会话天然是远程的:一旦工作器连接,Mission Control 就会在 https://github.com/copilot/tasks/{sessionId} 发布该会话,而运行时会发出一个 session.info 事件,并附带该 URL。 无需调用remote.enable() — 该 API 仅用于将本地会话提升到任务控制。

通过订阅 session.info 并按 infoType: "remote" 筛选来捕获 URL:

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存储库相关联:

领域必选Description
owner是的存储库所有者或组织。
name是的存储库名称。
branch要用于存储库上下文的分支。 省略它以允许运行时选择默认分支或当前存储库上下文。

存储库关联在 SDK 类型中是可选的,但只要应用知道目标存储库,就将其包含在内。 它有助于任务控制在正确的上下文中显示会话,并为云代理提供更清晰的起点。

当工作应从特定分支开始时使用 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 和路由

云会话使用派生自 GITHUB_COPILOT_INTEGRATION_ID 环境变量的 Copilot-Integration-Id 标头进行标记。 此集成 ID 由任务控制用于路由、归因和集成专属行为。

有关多用户服务器指南和完整的集成 ID 详细信息,请参阅 多租户与服务器部署

任务控制将 SDK 创建的云会话路由到 copilot-developer-sandbox 智能体数据域。 该名称是云端代理的内部路由标识,并不意味着该会话使用本地 Windows 沙盒环境。

高级:COPILOT_MC_BASE_URL

默认情况下,运行时会根据已配置的 Copilot API URL 推导出 Mission Control 的基础 URL。 仅当需要覆盖该任务控制终结点时才设置 COPILOT_MC_BASE_URL

GitHub Enterprise Server 部署可能需要此操作。 在将其用于生产环境之前,请先与您的 GitHub 代表确认正确的值和支持状态。

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

云会话与远程会话

Capability远程会话云会话
执行位置本地计算机或服务器GitHub托管的计算
任务控制角色与 GitHub Web/mobile 共享本地会话创建和路由托管会话
SDK 选项
remote: true 在客户端或会话中
cloud: { ... } 创建会话时
恢复路径标准简历标准简历
Windows 沙盒关系无关无关

当会话需要在已运行 SDK 运行时的环境中执行,并且还需要能够从 Mission Control 访问时,请使用远程会话。 在GitHub托管的计算上执行会话时,请使用云会话。

故障排除

症状可能的原因需要检查的事项
云会话创建返回 "policy_blocked"组织策略阻止从云流进行远程控制或查看检查组织的 Copilot 策略和用户授权资格
会话是在没有存储库上下文的情况下创建的
cloud.repository 已省略传递 ownername,以及可选的 branch
恢复将忽略新 cloud 选项
cloud 仅适用于新会话正常恢复现有会话
沙箱设置相关疑难问题Windows沙盒和云会话是分开的不要将 SANDBOX=true 用于云端执行
session.send 使用 messageId 进行解析,但没有触发 assistant.* 事件,任务控制也不显示命令提示session.send 早于来自远程工作进程的 session.start 执行;运行时吞掉了该提示在发送之前,等待第一个带有 producer === "copilot-agent"session.start 事件。 请参阅发送第一个提示词
尽管云端工作进程正在处理,实时界面却始终不更新未在 createSession 上设置 streaming,因此只会发出最后一个 assistant.messagecreateSession上设置streaming: true,然后重新启动
云会话有效,但 UI 中未显示可共享 URL应用从未针对该 URL 订阅 session.info订阅 session.info 并筛选 infoType === "remote"。 请参阅 访问任务控制 URL

另请参阅

  • 远程会话:通过任务控制共享本地托管会话
  •           [AUTOTITLE](/copilot/how-tos/copilot-sdk/features/streaming-events):订阅 `assistant.*` 增量以进行实时 UI 渲染
    
  • 多租户与服务器部署:集成 ID 和服务器部署模式
  • Authentication:为 SDK 会话配置GitHub身份验证