チュートリアル 2: Issue トリアージボット
サブコマンド: tutorial issue-triage
ソース: src/go/cmd/tutorial/issuetriage.go
学べること
- 構造体タグで型付きのツール入出力を宣言する方法
- 型から JSON スキーマを生成する
copilot.DefineToolでツールを作成する方法 SessionConfig.Toolsでセッションにツールを登録する方法- 1 つのプロンプトから複数のツール呼び出しを駆動するツール呼び出しエージェントループの仕組み
ToolExecutionStartDataイベントでツール呼び出しを観測する方法
前提条件
ステップ 1 — 型付きのツール入出力を宣言する
copilot.DefineTool は Go の関数をツールに変換します。引数と戻り値の型がツールの JSON スキーマになり、Copilot は呼び出し方を理解します。jsonschema 構造体タグはモデルに見せるフィールドの説明を提供し、json タグはワイヤフォーマットを制御します。
// list_issues は引数を取りません。
type listIssuesInput struct{}
type issueItem struct {
ID int `json:"id"`
Title string `json:"title"`
Body string `json:"body"`
Labels []string `json:"labels"`
}
type listIssuesOutput struct {
Issues []issueItem `json:"issues"`
}
type labelIssueInput struct {
IssueID int `json:"issue_id" jsonschema:"numeric ID of the issue to label"`
Labels []string `json:"labels" jsonschema:"labels to apply (e.g. bug, enhancement, documentation)"`
}
type labelIssueOutput struct {
Success bool `json:"success"`
IssueID int `json:"issue_id"`
AppliedLabels []string `json:"applied_labels"`
}
ステップ 2 — DefineTool でツールを作成する
copilot.DefineTool[T, U](name, description, handler) は入力型 T と出力型 U のジェネリックです。ハンドラはデコード済みの引数と copilot.ToolInvocation を受け取り、型付きの結果を返します。文字列以外の結果は自動的に JSON シリアライズされます。
var (
mu sync.Mutex
triaged []triageRecord
)
listIssues := copilot.DefineTool(
"list_issues",
"Return the list of open GitHub issues to triage.",
func(_ listIssuesInput, _ copilot.ToolInvocation) (listIssuesOutput, error) {
return listIssuesOutput{Issues: sampleIssues}, nil
},
)
labelIssue := copilot.DefineTool(
"label_issue",
"Apply one or more labels to a GitHub issue.",
func(in labelIssueInput, _ copilot.ToolInvocation) (labelIssueOutput, error) {
mu.Lock()
triaged = append(triaged, triageRecord{ID: in.IssueID, Labels: in.Labels})
mu.Unlock()
return labelIssueOutput{Success: true, IssueID: in.IssueID, AppliedLabels: in.Labels}, nil
},
)
注意: ツールハンドラは異なるゴルーチンから呼び出される可能性があるため、共有状態(ここでは
triagedスライス)はsync.Mutexで保護してください。
ステップ 3 — セッションにツールを登録する
ツールを SessionConfig.Tools に渡します。システムメッセージで Copilot に使い方を伝えます。この実行では最終的な要約だけが必要で逐次トークンは不要なため、Streaming: copilot.Bool(false) を使います。
session, err := client.CreateSession(ctx, &copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
Tools: []copilot.Tool{listIssues, labelIssue},
Streaming: copilot.Bool(false),
SystemMessage: &copilot.SystemMessageConfig{
Mode: "replace",
Content: "You are an expert GitHub issue triage assistant. " +
"Use list_issues to fetch open issues, classify each one as 'bug', " +
"'enhancement', or 'documentation', then call label_issue to apply the " +
"appropriate label. After triaging all issues, summarise your actions.",
},
})
注意:
Mode: "replace"はシステムメッセージを完全に差し替えます。カスタムツールが登録されているため、各ツール実行の前にOnPermissionRequestが発火します。ApproveAllはすべての呼び出しを通します。
ステップ 4 — イベントでツール呼び出しを観測する
イベントハンドラを登録してエージェントの動作を監視します。ToolExecutionStartData は Copilot がツールを呼び出すたびに発火します。
session.On(func(event copilot.SessionEvent) {
switch data := event.Data.(type) {
case *copilot.ToolExecutionStartData:
fmt.Fprintf(os.Stderr, "[Tool] Calling: %s\n", data.ToolName)
case *copilot.SessionErrorData:
fmt.Fprintf(os.Stderr, "[Error] %s\n", data.Message)
}
})
ステップ 5 — トリアージのターンを実行して結果を集める
1 つのプロンプトがエージェントループを開始します。Copilot は list_issues を呼び、各項目を分類し、それぞれに label_issue を呼び、最後に要約を返します。SendPromptAndWait はセッションがアイドルになるまでブロックします。
reply, err := session.SendPromptAndWait(ctx, "Please triage all open issues and apply the appropriate labels.")
if err != nil {
return err
}
content := "(no response)"
if reply != nil {
if data, ok := reply.Data.(*copilot.AssistantMessageData); ok {
content = data.Content
}
}
mu.Lock()
applied := triaged
mu.Unlock()
labelsJSON, _ := json.MarshalIndent(applied, "", " ")
fmt.Println("=== Triage Summary ===")
fmt.Println(content)
fmt.Println("\n=== Applied Labels ===")
fmt.Println(string(labelsJSON))
サブコマンドの実行
まず CLI をビルドし、src/go ディレクトリから issue-triage サブコマンドを実行します。
cd src/go
make build
# 組み込みのサンプル Issue をトリアージ
./dist/template-github-copilot-go tutorial issue-triage
# スタンドアロンの CLI サーバーに接続(任意 — TCP モードで稼働中の場合のみ)
./dist/template-github-copilot-go tutorial issue-triage --cli-url localhost:3000
フラグ
| フラグ | 短縮形 | デフォルト | 説明 |
|---|---|---|---|
--cli-url |
-c |
(空) | 任意の Copilot CLI サーバー URL(例: localhost:3000) |
グローバルな
--verbose/-vフラグはログレベルをDEBUGに下げ、クライアント接続モードとセッションのライフサイクルを表示します。
次のステップ
- チュートリアル 3 — ストリーミングレビュー: レスポンスをトークンごとにストリーミングする
- チュートリアル 5 — 監査ログ: カスタムパーミッションハンドラでツール呼び出しを拒否する
- pkg.go.dev で Go API 全体を参照