← 새소식으로 돌아가기

"sessioncast-go v0.1.0 — SessionCast 릴레이용 Go SDK"

sessioncast-go를 릴리즈합니다. SessionCast 릴레이 서버와 통신하는 Go 클라이언트 라이브러리이며, OpenCode의 SessionCast 프로바이더를 구동하는 동일한 라이브러리입니다.

설치

go get github.com/sessioncast/sessioncast-go

기능

sessioncast-go는 WebSocket으로 SessionCast 릴레이에 연결하여, 로컬 CLI 에이전트의 기능을 Go 프로그램에서 호출할 수 있습니다:

  • LLM Chat — 프롬프트 전송, 에이전트에 설정된 LLM으로 응답 수신
  • LLM Streaming — 채널을 통한 청크 단위 스트리밍
  • Remote Exec — 에이전트 머신에서 셸 명령어 실행
  • SendKeys — tmux 세션에 키 입력 전송
  • List Sessions — 활성 tmux 세션 조회
  • Capability Negotiation — 연결된 에이전트의 지원 기능 확인

Quick Start

package main

import (
    "context"
    "fmt"
    "log"

    sessioncast "github.com/sessioncast/sessioncast-go"
)

func main() {
    client := sessioncast.NewClient(
        sessioncast.WithRelayURL("wss://relay.sessioncast.io/ws"),
        sessioncast.WithToken("agt_YOUR_TOKEN"),
        sessioncast.WithMachineID("my-machine"),
    )

    ctx := context.Background()
    if err := client.Connect(ctx); err != nil {
        log.Fatal(err)
    }
    defer client.Disconnect()

    // Chat completion
    resp, err := client.LlmChat(ctx, &sessioncast.LlmChatRequest{
        Model: "claude-code",
        Messages: []sessioncast.ChatMessage{
            {Role: "user", Content: "What is Docker? Answer in 2 sentences."},
        },
    })
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(resp.Choices[0].Message.Content)
}

스트리밍

stream, err := client.LlmChatStream(ctx, &sessioncast.LlmChatRequest{
    Model:    "claude-code",
    Messages: []sessioncast.ChatMessage{
        {Role: "user", Content: "Write a hello world HTTP server in Go."},
    },
})
if err != nil {
    log.Fatal(err)
}

for event := range stream {
    if event.Error != nil {
        log.Fatal(event.Error)
    }
    if event.Chunk != nil {
        fmt.Print(event.Chunk.Content)
    }
    if event.Response != nil {
        fmt.Printf("\n\n토큰 사용량: %d\n", event.Response.Usage.TotalTokens)
    }
}

원격 실행

result, err := client.Exec(ctx, &sessioncast.ExecRequest{
    Command: "ls -la /tmp",
    Cwd:     "/home/user",
})
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Exit code: %d\nStdout:\n%s\n", result.ExitCode, result.Stdout)

자동 재연결

장시간 실행되는 서비스에는 ConnectWithReconnect를 사용하세요 — 지수 백오프(1초 → 2초 → 4초 → ... → 최대 30초)로 자동 재연결합니다:

client.ConnectWithReconnect(ctx, func() {
    fmt.Println("연결됨!")
})

아키텍처

Go 앱
  → sessioncast-go (이 라이브러리)
    → WebSocket → SessionCast Relay
      → CLI Agent (대상 머신)
        → LLM / Shell / tmux

연결 수명 관리, ping/pong 킵얼라이브(30초 간격), UUID 기반 요청-응답 매칭, 캐퍼빌리티 협상, 타임아웃 관리를 처리합니다.

패키지 구조

  • client.go — WebSocket 클라이언트, 연결/해제, 메시지 라우팅
  • llm.goLlmChat(), LlmChatStream()
  • exec.goExec(), SendKeys(), ListSessions()
  • protocol.go — 메시지 타입, 요청/응답 구조체
  • correlator.go — UUID 기반 요청-응답 매칭
  • capability.go — 캐퍼빌리티 협상 핸드셰이크
  • reconnect.go — 지수 백오프 자동 재연결

의존성

두 개만 사용합니다:

  • github.com/gorilla/websocket — WebSocket 클라이언트
  • github.com/google/uuid — 요청 ID 생성

설정

Functional Options 패턴으로 구성합니다:

sessioncast.NewClient(
    sessioncast.WithRelayURL("wss://relay.sessioncast.io/ws"),
    sessioncast.WithToken("agt_YOUR_TOKEN"),
    sessioncast.WithMachineID("my-machine"),
    sessioncast.WithAgentID("my-agent"),
    sessioncast.WithLabel("My App"),
    sessioncast.WithRequestTimeout(120 * time.Second),
    sessioncast.WithPingInterval(30 * time.Second),
    sessioncast.WithLogger(slog.Default()),
)

링크

불러오는 중...