fix(providers): fix GitHub Copilot provider session lifecycle and response handling
- Store client as struct field to prevent premature garbage collection - Remove defer client.Stop() from constructor which was killing the gRPC client immediately after NewGitHubCopilotProvider returned, causing all subsequent Chat() calls to silently fail - Add proper error handling for CreateSession (was ignoring error with _) - Replace session.Send() with session.SendAndWait(): Send() only returns a message UUID, not the response text; SendAndWait() blocks until the assistant is idle and returns the actual SessionEvent with content - Add Close() method for proper client lifecycle management - Add 15s connection timeout to fail fast if CLI is unreachable
This commit is contained in:
parent
e883e14b81
commit
9bf6199c5f
1 changed files with 38 additions and 15 deletions
|
|
@ -2,56 +2,70 @@ package providers
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
json "encoding/json"
|
||||
|
||||
copilot "github.com/github/copilot-sdk/go"
|
||||
)
|
||||
|
||||
type GitHubCopilotProvider struct {
|
||||
uri string
|
||||
connectMode string // `stdio` or `grpc``
|
||||
connectMode string // `stdio` or `grpc`
|
||||
|
||||
client *copilot.Client
|
||||
session *copilot.Session
|
||||
}
|
||||
|
||||
func NewGitHubCopilotProvider(uri string, connectMode string, model string) (*GitHubCopilotProvider, error) {
|
||||
|
||||
var session *copilot.Session
|
||||
var client *copilot.Client
|
||||
if connectMode == "" {
|
||||
connectMode = "grpc"
|
||||
}
|
||||
switch connectMode {
|
||||
|
||||
case "stdio":
|
||||
// todo
|
||||
//todo
|
||||
case "grpc":
|
||||
client := copilot.NewClient(&copilot.ClientOptions{
|
||||
client = copilot.NewClient(&copilot.ClientOptions{
|
||||
CLIUrl: uri,
|
||||
})
|
||||
if err := client.Start(context.Background()); err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"Can't connect to Github Copilot, https://github.com/github/copilot-sdk/blob/main/docs/getting-started.md#connecting-to-an-external-cli-server for details",
|
||||
)
|
||||
connectCtx, connectCancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||
defer connectCancel()
|
||||
if err := client.Start(connectCtx); err != nil {
|
||||
return nil, fmt.Errorf("can't connect to Github Copilot: %w", err)
|
||||
}
|
||||
defer client.Stop()
|
||||
session, _ = client.CreateSession(context.Background(), &copilot.SessionConfig{
|
||||
var err error
|
||||
session, err = client.CreateSession(connectCtx, &copilot.SessionConfig{
|
||||
Model: model,
|
||||
Hooks: &copilot.SessionHooks{},
|
||||
})
|
||||
if err != nil {
|
||||
client.Stop()
|
||||
return nil, fmt.Errorf("failed to create Copilot session: %w", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return &GitHubCopilotProvider{
|
||||
uri: uri,
|
||||
connectMode: connectMode,
|
||||
client: client,
|
||||
session: session,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p *GitHubCopilotProvider) Close() {
|
||||
if p.client != nil {
|
||||
p.client.Stop()
|
||||
}
|
||||
}
|
||||
|
||||
// Chat sends a chat request to GitHub Copilot
|
||||
func (p *GitHubCopilotProvider) Chat(
|
||||
ctx context.Context, messages []Message, tools []ToolDefinition, model string, options map[string]any,
|
||||
) (*LLMResponse, error) {
|
||||
func (p *GitHubCopilotProvider) Chat(ctx context.Context, messages []Message, tools []ToolDefinition, model string, options map[string]interface{}) (*LLMResponse, error) {
|
||||
type tempMessage struct {
|
||||
Role string `json:"role"`
|
||||
Content string `json:"content"`
|
||||
|
|
@ -67,16 +81,25 @@ func (p *GitHubCopilotProvider) Chat(
|
|||
|
||||
fullcontent, _ := json.Marshal(out)
|
||||
|
||||
content, _ := p.session.Send(ctx, copilot.MessageOptions{
|
||||
event, err := p.session.SendAndWait(ctx, copilot.MessageOptions{
|
||||
Prompt: string(fullcontent),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("copilot error: %w", err)
|
||||
}
|
||||
|
||||
if event == nil || event.Data.Content == nil {
|
||||
return nil, fmt.Errorf("empty response from Copilot")
|
||||
}
|
||||
|
||||
return &LLMResponse{
|
||||
FinishReason: "stop",
|
||||
Content: content,
|
||||
Content: *event.Data.Content,
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
func (p *GitHubCopilotProvider) GetDefaultModel() string {
|
||||
|
||||
return "gpt-4.1"
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue