copilot-sdk-supercharged 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +301 -0
- data/lib/copilot/client.rb +825 -0
- data/lib/copilot/define_tool.rb +82 -0
- data/lib/copilot/json_rpc_client.rb +326 -0
- data/lib/copilot/sdk_protocol_version.rb +16 -0
- data/lib/copilot/session.rb +299 -0
- data/lib/copilot/types.rb +484 -0
- data/lib/copilot/version.rb +7 -0
- data/lib/copilot.rb +28 -0
- metadata +58 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 89d18c0ed24efd53b41059356f64e3f0194336f9a9916a46d6848619dc0b91d1
|
|
4
|
+
data.tar.gz: 43b3bde04215480b3bf8eb61394fb8e81667240162c11c98659c07c63ee416e7
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 1c3047beed3644b182ad7148c0e410df8a2c5e7eb013bb4651b8453b66843e68ab872b06bdc63654ee173861d0e438240beccb44ed0c626e7a0407a87d595a00
|
|
7
|
+
data.tar.gz: 1bc2cb8dd53d08a2c4c2d80cd39481347cc36fed6f26d589023f6b9b04e4ca841ef79fc776922aeea0b5c860fceb1cde077ef7eead79a5d9ed85337c7366dfdb
|
data/README.md
ADDED
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
# Copilot Supercharged Ruby SDK
|
|
2
|
+
|
|
3
|
+
Ruby SDK for the [GitHub Copilot CLI](https://github.com/github/copilot). Communicates with the Copilot CLI server via JSON-RPC 2.0 over stdio or TCP.
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
- Ruby >= 3.1
|
|
8
|
+
- GitHub Copilot CLI installed and authenticated
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
Add to your Gemfile:
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
gem "copilot-sdk-supercharged"
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Or install directly:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
gem install copilot-sdk-supercharged
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
```ruby
|
|
27
|
+
require "copilot"
|
|
28
|
+
|
|
29
|
+
# Create a client (spawns the CLI server process)
|
|
30
|
+
client = Copilot::CopilotClient.new(
|
|
31
|
+
cli_path: "/usr/local/bin/copilot",
|
|
32
|
+
log_level: "info"
|
|
33
|
+
)
|
|
34
|
+
client.start
|
|
35
|
+
|
|
36
|
+
# Create a session
|
|
37
|
+
session = client.create_session(model: "gpt-4")
|
|
38
|
+
|
|
39
|
+
# Subscribe to events
|
|
40
|
+
unsub = session.on do |event|
|
|
41
|
+
if event.type == Copilot::SessionEventType::ASSISTANT_MESSAGE
|
|
42
|
+
puts event.data["content"]
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Send a message and wait for the response
|
|
47
|
+
response = session.send_and_wait(prompt: "Hello, world!")
|
|
48
|
+
|
|
49
|
+
# Clean up
|
|
50
|
+
unsub.call
|
|
51
|
+
session.destroy
|
|
52
|
+
client.stop
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Connecting to an External Server
|
|
56
|
+
|
|
57
|
+
Instead of spawning a CLI process, connect to an already-running server:
|
|
58
|
+
|
|
59
|
+
```ruby
|
|
60
|
+
client = Copilot::CopilotClient.new(cli_url: "localhost:8080")
|
|
61
|
+
client.start
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Custom Tools
|
|
65
|
+
|
|
66
|
+
Register tools that the assistant can invoke:
|
|
67
|
+
|
|
68
|
+
```ruby
|
|
69
|
+
weather_tool = Copilot.define_tool(
|
|
70
|
+
name: "get_weather",
|
|
71
|
+
description: "Get weather for a city",
|
|
72
|
+
parameters: {
|
|
73
|
+
type: "object",
|
|
74
|
+
properties: {
|
|
75
|
+
city: { type: "string", description: "City name" }
|
|
76
|
+
},
|
|
77
|
+
required: ["city"]
|
|
78
|
+
}
|
|
79
|
+
) do |args, invocation|
|
|
80
|
+
city = args["city"]
|
|
81
|
+
"It is 22 degrees and sunny in #{city}."
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
session = client.create_session(tools: [weather_tool])
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Tool handlers can return:
|
|
88
|
+
- A **String** (wrapped as a successful result)
|
|
89
|
+
- A **Hash** (passed through if it has `textResultForLlm`, otherwise JSON-serialized)
|
|
90
|
+
- A **`Copilot::ToolResult`** struct for full control over result type, errors, and telemetry
|
|
91
|
+
|
|
92
|
+
## Permission Handling
|
|
93
|
+
|
|
94
|
+
Handle permission requests when the assistant wants to perform privileged operations:
|
|
95
|
+
|
|
96
|
+
```ruby
|
|
97
|
+
session = client.create_session(
|
|
98
|
+
on_permission_request: ->(request, ctx) {
|
|
99
|
+
puts "Permission requested: #{request.kind}"
|
|
100
|
+
Copilot::PermissionRequestResult.new(kind: Copilot::PermissionKind::APPROVED)
|
|
101
|
+
}
|
|
102
|
+
)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## User Input
|
|
106
|
+
|
|
107
|
+
Enable the `ask_user` tool so the agent can ask questions:
|
|
108
|
+
|
|
109
|
+
```ruby
|
|
110
|
+
session = client.create_session(
|
|
111
|
+
on_user_input_request: ->(request, ctx) {
|
|
112
|
+
puts "Agent asks: #{request.question}"
|
|
113
|
+
print "> "
|
|
114
|
+
answer = $stdin.gets.chomp
|
|
115
|
+
Copilot::UserInputResponse.new(answer: answer, was_freeform: true)
|
|
116
|
+
}
|
|
117
|
+
)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Hooks
|
|
121
|
+
|
|
122
|
+
Intercept session lifecycle events with hooks:
|
|
123
|
+
|
|
124
|
+
```ruby
|
|
125
|
+
hooks = Copilot::SessionHooks.new(
|
|
126
|
+
on_pre_tool_use: ->(input, ctx) {
|
|
127
|
+
puts "About to call tool: #{input['toolName']}"
|
|
128
|
+
# Return nil to proceed normally, or a hash with modifiedArgs, etc.
|
|
129
|
+
nil
|
|
130
|
+
},
|
|
131
|
+
on_post_tool_use: ->(input, ctx) {
|
|
132
|
+
puts "Tool #{input['toolName']} completed"
|
|
133
|
+
nil
|
|
134
|
+
},
|
|
135
|
+
on_session_start: ->(input, ctx) {
|
|
136
|
+
puts "Session started from: #{input['source']}"
|
|
137
|
+
nil
|
|
138
|
+
}
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
session = client.create_session(hooks: hooks)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Event Subscriptions
|
|
145
|
+
|
|
146
|
+
### Session Events
|
|
147
|
+
|
|
148
|
+
Subscribe to all events or specific event types:
|
|
149
|
+
|
|
150
|
+
```ruby
|
|
151
|
+
# All events
|
|
152
|
+
unsub = session.on { |event| puts event.type }
|
|
153
|
+
|
|
154
|
+
# Specific event type
|
|
155
|
+
unsub = session.on(Copilot::SessionEventType::ASSISTANT_MESSAGE) do |event|
|
|
156
|
+
puts event.data["content"]
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Unsubscribe
|
|
160
|
+
unsub.call
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Lifecycle Events (Client-Level)
|
|
164
|
+
|
|
165
|
+
Monitor session lifecycle changes (useful in TUI+server mode):
|
|
166
|
+
|
|
167
|
+
```ruby
|
|
168
|
+
unsub = client.on(Copilot::SessionLifecycleEventType::SESSION_CREATED) do |event|
|
|
169
|
+
puts "Session created: #{event.session_id}"
|
|
170
|
+
end
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Session Management
|
|
174
|
+
|
|
175
|
+
```ruby
|
|
176
|
+
# List all sessions
|
|
177
|
+
sessions = client.list_sessions
|
|
178
|
+
sessions.each { |s| puts "#{s.session_id}: #{s.summary}" }
|
|
179
|
+
|
|
180
|
+
# Resume a session
|
|
181
|
+
session = client.resume_session("session-id-here")
|
|
182
|
+
|
|
183
|
+
# Delete a session
|
|
184
|
+
client.delete_session("session-id-here")
|
|
185
|
+
|
|
186
|
+
# Get last session ID
|
|
187
|
+
last_id = client.get_last_session_id
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Custom Providers (BYOK)
|
|
191
|
+
|
|
192
|
+
Use your own API endpoint:
|
|
193
|
+
|
|
194
|
+
```ruby
|
|
195
|
+
session = client.create_session(
|
|
196
|
+
model: "my-model",
|
|
197
|
+
provider: Copilot::ProviderConfig.new(
|
|
198
|
+
type: "openai",
|
|
199
|
+
base_url: "https://api.example.com/v1",
|
|
200
|
+
api_key: "sk-..."
|
|
201
|
+
)
|
|
202
|
+
)
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## MCP Servers
|
|
206
|
+
|
|
207
|
+
Configure Model Context Protocol servers:
|
|
208
|
+
|
|
209
|
+
```ruby
|
|
210
|
+
session = client.create_session(
|
|
211
|
+
mcp_servers: {
|
|
212
|
+
"my-server" => {
|
|
213
|
+
tools: ["*"],
|
|
214
|
+
command: "npx",
|
|
215
|
+
args: ["-y", "@example/mcp-server"],
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
)
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Infinite Sessions
|
|
222
|
+
|
|
223
|
+
Enable automatic context compaction for long-running sessions:
|
|
224
|
+
|
|
225
|
+
```ruby
|
|
226
|
+
session = client.create_session(
|
|
227
|
+
infinite_sessions: Copilot::InfiniteSessionConfig.new(
|
|
228
|
+
enabled: true,
|
|
229
|
+
background_compaction_threshold: 0.80,
|
|
230
|
+
buffer_exhaustion_threshold: 0.95
|
|
231
|
+
)
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
# Access workspace path for persisted state
|
|
235
|
+
puts session.workspace_path
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## Streaming
|
|
239
|
+
|
|
240
|
+
Enable streaming to receive incremental message chunks:
|
|
241
|
+
|
|
242
|
+
```ruby
|
|
243
|
+
session = client.create_session(streaming: true)
|
|
244
|
+
|
|
245
|
+
session.on(Copilot::SessionEventType::ASSISTANT_MESSAGE_DELTA) do |event|
|
|
246
|
+
print event.data["deltaContent"]
|
|
247
|
+
end
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## API Reference
|
|
251
|
+
|
|
252
|
+
### `Copilot::CopilotClient`
|
|
253
|
+
|
|
254
|
+
| Method | Description |
|
|
255
|
+
|--------|-------------|
|
|
256
|
+
| `start` | Start the CLI server and connect |
|
|
257
|
+
| `stop` | Graceful shutdown, returns array of errors |
|
|
258
|
+
| `force_stop` | Forceful shutdown |
|
|
259
|
+
| `create_session(**config)` | Create a new session |
|
|
260
|
+
| `resume_session(id, **config)` | Resume an existing session |
|
|
261
|
+
| `ping(message = nil)` | Ping the server |
|
|
262
|
+
| `get_status` | Get CLI version and protocol info |
|
|
263
|
+
| `get_auth_status` | Get authentication status |
|
|
264
|
+
| `list_models` | List available models (cached) |
|
|
265
|
+
| `list_sessions` | List all sessions |
|
|
266
|
+
| `get_last_session_id` | Get most recently updated session ID |
|
|
267
|
+
| `delete_session(id)` | Permanently delete a session |
|
|
268
|
+
| `get_foreground_session_id` | Get TUI foreground session |
|
|
269
|
+
| `set_foreground_session_id(id)` | Set TUI foreground session |
|
|
270
|
+
| `on(event_type = nil, &block)` | Subscribe to lifecycle events |
|
|
271
|
+
|
|
272
|
+
### `Copilot::CopilotSession`
|
|
273
|
+
|
|
274
|
+
| Method | Description |
|
|
275
|
+
|--------|-------------|
|
|
276
|
+
| `send(prompt:, attachments:, mode:)` | Send a message |
|
|
277
|
+
| `send_and_wait(prompt:, timeout:)` | Send and wait for idle |
|
|
278
|
+
| `on(event_type = nil, &block)` | Subscribe to session events |
|
|
279
|
+
| `get_messages` | Get conversation history |
|
|
280
|
+
| `destroy` | Destroy the session |
|
|
281
|
+
| `abort` | Abort current processing |
|
|
282
|
+
|
|
283
|
+
### Key Types
|
|
284
|
+
|
|
285
|
+
- `Copilot::Tool` - Tool definition with handler
|
|
286
|
+
- `Copilot::ToolResult` - Structured tool result
|
|
287
|
+
- `Copilot::SessionEvent` - Session event with type and data
|
|
288
|
+
- `Copilot::ModelInfo` - Model metadata
|
|
289
|
+
- `Copilot::ProviderConfig` - Custom API provider config
|
|
290
|
+
- `Copilot::SessionHooks` - Hook handlers
|
|
291
|
+
- `Copilot::InfiniteSessionConfig` - Infinite session settings
|
|
292
|
+
|
|
293
|
+
## Threading Model
|
|
294
|
+
|
|
295
|
+
The SDK uses a background reader thread for the JSON-RPC connection. Event handlers and tool handlers are called from this reader thread. If you need to interact with non-thread-safe resources, use appropriate synchronization (Mutex, Queue, etc.).
|
|
296
|
+
|
|
297
|
+
The `send_and_wait` method uses a `Mutex` + `ConditionVariable` to block the calling thread until the session becomes idle, which is the recommended pattern for synchronous usage.
|
|
298
|
+
|
|
299
|
+
## License
|
|
300
|
+
|
|
301
|
+
MIT - see [LICENSE](../LICENSE) for details.
|