Skip to content

Add Go cloud session SDK API#1257

Closed
JasonEtco wants to merge 1 commit into
mainfrom
jasonetco/go-cloud-session-sdk
Closed

Add Go cloud session SDK API#1257
JasonEtco wants to merge 1 commit into
mainfrom
jasonetco/go-cloud-session-sdk

Conversation

@JasonEtco
Copy link
Copy Markdown

Implement the Mission Control cloud task/client-control API for the Go SDK, matching the Node SDK behavior from #1256.

What's new

Types (cloud_types.go)

  • CloudRepository, CloudSessionMetadata, CloudSessionOptions, CloudConnectOptions
  • MissionControlTask, MissionControlTaskSession
  • MissionControlCommandType constants for all steering commands
  • CloudSessionError with reason categorization
  • Steering payload types: CloudPermissionResponsePayload, CloudAskUserResponsePayload, CloudElicitationResponsePayload, CloudPlanApprovalResponsePayload, CloudModeSwitchPayload

Mission Control HTTP client (cloud_mission_control_client.go)

  • createCloudTask — POST /tasks with repo or owner body
  • listTaskEvents — GET /tasks/:id/events
  • steerTask — POST /tasks/:id/steer
  • getTask — GET /tasks/:id (returns nil for 404)
  • Error extraction from JSON message field, status-based reason mapping

CloudSession (cloud_session.go)

  • Event polling with configurable interval and initial-event wait
  • Chronological sorting and deduplication
  • Handler registration with unsubscribe closures
  • Send, SendAndWait, Abort, SubmitRemoteCommand
  • Typed response helpers: RespondToPermission, RespondToAskUser, RespondToElicitation, RespondToPlanApproval, SwitchMode
  • remote_steerable_changed event tracking

Client methods (cloud_client.go)

  • CreateCloudSession(options) — creates MC task and returns *CloudSession
  • ConnectCloudSession(taskID, options) — attaches to existing task
  • Env-var fallback chain for MC URLs and tokens
  • Uses X-Copilot-Agent-Slug: copilot-developer-sandbox

Tests (cloud_session_test.go)

11 test cases covering task creation, steering, event dedup, error handling, disconnect, remote-steerable, and handler lifecycle.

README updates

CloudSession API reference, usage examples, and env var docs.

Implement the Mission Control cloud task/client-control API for the Go
SDK, matching the Node SDK behavior from PR #1256.

New files:
- cloud_types.go: CloudRepository, CloudSessionMetadata, CloudSessionOptions,
  CloudConnectOptions, MissionControlTask, MissionControlCommandType,
  CloudSessionError, and all steering payload types
- cloud_mission_control_client.go: HTTP client for Mission Control (create
  task, list events, steer, get task, frontend URL)
- cloud_session.go: CloudSession with event polling, deduplication, handler
  dispatch, steering helpers, and connect/disconnect lifecycle
- cloud_client.go: CreateCloudSession and ConnectCloudSession methods on
  Client, env-var resolution for MC URLs/tokens
- cloud_session_test.go: Unit tests covering task creation (with repo and
  repo-less), owner validation, steer API, event sorting/dedup, error
  responses, disconnect behavior, remote-steerable changes, handler
  subscribe/unsubscribe, and MC error extraction

Updated:
- README.md: CloudSession API reference, CloudSessionOptions docs, cloud
  session usage examples, environment variable docs

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 11, 2026 15:30
@JasonEtco JasonEtco requested a review from a team as a code owner May 11, 2026 15:30
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a Go SDK “cloud session” API for creating and remotely controlling Mission Control cloud sandbox tasks (no local CLI process), aligning with the previously added Node SDK behavior.

Changes:

  • Introduces Go types for Mission Control tasks/events, steering command payloads, and structured cloud-session errors.
  • Adds a Mission Control HTTP client plus Client.CreateCloudSession / Client.ConnectCloudSession helpers that construct and connect a CloudSession.
  • Implements CloudSession event polling, event dedupe/sorting, handler subscription, and steering helpers; adds focused unit tests and README documentation.
Show a summary per file
File Description
go/README.md Documents the new CloudSession API surface, options, env vars, and examples.
go/cloud_types.go Defines cloud session/task/event types, steering command constants, payload types, and CloudSessionError.
go/cloud_mission_control_client.go Implements Mission Control HTTP requests for task create/get/events/steer and error extraction.
go/cloud_session.go Implements CloudSession polling, event storage/dedupe, handler subscriptions, and steering methods.
go/cloud_client.go Adds Client.CreateCloudSession / ConnectCloudSession and MC client/env-var plumbing + metadata builders.
go/cloud_session_test.go Adds unit tests covering task creation/connection, steering, dedupe/sorting, errors, disconnect, and handlers.

Copilot's findings

Comments suppressed due to low confidence (1)

go/cloud_session_test.go:469

  • capture reads the body using r.ContentLength and a single r.Body.Read, which can result in partial reads and can fail if ContentLength == -1. Using io.ReadAll(r.Body) (with error handling) will make these request-capture assertions more robust.
func capture(r *http.Request) capturedRequest {
	body := make([]byte, 0)
	if r.Body != nil {
		body = make([]byte, r.ContentLength)
		r.Body.Read(body)
	}
  • Files reviewed: 6/6 changed files
  • Comments generated: 6

Comment thread go/cloud_session.go
Comment on lines +412 to +416
cs.seenEventIDs[e.ID] = true
cs.events = append(cs.events, e)
cs.markEventTimestamp(e)
cs.updateRemoteSteerable(e)
cs.dispatchEvent(e)
Comment thread go/cloud_session.go
cs.mu.Unlock()
return errors.New("cloud session is disconnected")
}
cs.mu.Unlock()
Comment thread go/cloud_session.go
}

// Connect fetches initial events and starts background polling.
// It must be called before sending messages or subscribing to events.
Comment thread go/cloud_client.go
Comment on lines +229 to +232

createdAt, _ := time.Parse(time.RFC3339, task.CreatedAt)
updatedAt, _ := time.Parse(time.RFC3339, task.UpdatedAt)

Comment on lines +227 to +231
req.Header.Set(k, v)
}

client := &http.Client{Timeout: timeout}
resp, err := client.Do(req)
Comment thread go/cloud_session_test.go
Comment on lines +181 to +183
b := make([]byte, r.ContentLength)
r.Body.Read(b)
capturedBody = b
@github-actions
Copy link
Copy Markdown
Contributor

Cross-SDK Consistency Review

This PR adds the CloudSession API to the Go SDK, matching the Node SDK implementation from #1256. Overall the implementation is well-aligned — types, field names, wire values, method signatures, env-var chains, and progress phases all match their Node equivalents (adjusted for Go idioms).

✅ Consistent with Node SDK

  • CloudRepository, CloudProgressPhase constants, MissionControlCommandType string values
  • CloudSessionOptions and CloudConnectOptions fields
  • CreateCloudSession / ConnectCloudSession method signatures
  • Send, SendAndWait, Abort, Disconnect, SubmitRemoteCommand
  • Typed response helpers (RespondToPermission, RespondToAskUser, RespondToElicitation, RespondToPlanApproval, SwitchMode)
  • GetMessages / getMessages returning all received events
  • Env-var fallback chain (COPILOT_MC_BASE_URL, COPILOT_API_BASE_URL, COPILOT_MC_ACCESS_TOKEN, COPILOT_MC_FRONTEND_URL)

⚠️ Minor API gap vs Node SDK

The Node CloudSession.on() supports a typed event-type filter overload (e.g. session.on("assistant.message", handler)), which is also documented in the Node README for CloudSession. The Go On() only accepts a wildcard handler. This is internally consistent with Go's existing Session.On(), but callers wanting typed subscriptions have to filter manually in their handler. See the inline comment for a suggestion.

📋 Feature parity for Python and .NET

Neither Python (python/copilot/) nor .NET (dotnet/src/) has an equivalent CloudSession implementation yet. These will need follow-up PRs to maintain cross-SDK feature parity. Suggested API surface:

  • Python: client.create_cloud_session(options) / client.connect_cloud_session(task_id, options) returning a CloudSession object
  • .NET: client.CreateCloudSessionAsync(options) / client.ConnectCloudSessionAsync(taskId, options) returning a CloudSession object

Generated by SDK Consistency Review Agent for issue #1257 · ● 1.5M ·

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generated by SDK Consistency Review Agent for issue #1257 · ● 1.5M

Comment thread go/cloud_session.go

// On registers a handler that is called for every cloud session event.
// Returns an unsubscribe function.
func (cs *CloudSession) On(handler CloudSessionEventHandler) func() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cross-SDK consistency note: The Node SDK's CloudSession.on() supports a typed event-filter overload:

// Node SDK - typed subscription
session.on("assistant.message", (event) => {
    console.log(event.data.content);
});

// Node SDK - wildcard
session.on((event) => { ... });

The Go CloudSession only exposes the wildcard form. This is consistent with the existing pattern in the Go SDK's regular Session.On(), but it does diverge from what the Node README documents for CloudSession.

Consider adding an OnEventType(eventType string, handler CloudSessionEventHandler) func() method (mirroring the Client.OnEventType pattern already present in the Go SDK) so callers can subscribe to specific event types without filtering in every handler. This would bring the Go CloudSession API surface closer to Node's.

@JasonEtco JasonEtco closed this May 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants