tsikol 0.1.0
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/CHANGELOG.md +22 -0
- data/CONTRIBUTING.md +84 -0
- data/LICENSE +21 -0
- data/README.md +579 -0
- data/Rakefile +12 -0
- data/docs/README.md +69 -0
- data/docs/api/middleware.md +721 -0
- data/docs/api/prompt.md +858 -0
- data/docs/api/resource.md +651 -0
- data/docs/api/server.md +509 -0
- data/docs/api/test-helpers.md +591 -0
- data/docs/api/tool.md +527 -0
- data/docs/cookbook/authentication.md +651 -0
- data/docs/cookbook/caching.md +877 -0
- data/docs/cookbook/dynamic-tools.md +970 -0
- data/docs/cookbook/error-handling.md +887 -0
- data/docs/cookbook/logging.md +1044 -0
- data/docs/cookbook/rate-limiting.md +717 -0
- data/docs/examples/code-assistant.md +922 -0
- data/docs/examples/complete-server.md +726 -0
- data/docs/examples/database-manager.md +1198 -0
- data/docs/examples/devops-tools.md +1382 -0
- data/docs/examples/echo-server.md +501 -0
- data/docs/examples/weather-service.md +822 -0
- data/docs/guides/completion.md +472 -0
- data/docs/guides/getting-started.md +462 -0
- data/docs/guides/middleware.md +823 -0
- data/docs/guides/project-structure.md +434 -0
- data/docs/guides/prompts.md +920 -0
- data/docs/guides/resources.md +720 -0
- data/docs/guides/sampling.md +804 -0
- data/docs/guides/testing.md +863 -0
- data/docs/guides/tools.md +627 -0
- data/examples/README.md +92 -0
- data/examples/advanced_features.rb +129 -0
- data/examples/basic-migrated/app/prompts/weather_chat.rb +44 -0
- data/examples/basic-migrated/app/resources/weather_alerts.rb +18 -0
- data/examples/basic-migrated/app/tools/get_current_weather.rb +34 -0
- data/examples/basic-migrated/app/tools/get_forecast.rb +30 -0
- data/examples/basic-migrated/app/tools/get_weather_by_coords.rb +48 -0
- data/examples/basic-migrated/server.rb +25 -0
- data/examples/basic.rb +73 -0
- data/examples/full_featured.rb +175 -0
- data/examples/middleware_example.rb +112 -0
- data/examples/sampling_example.rb +104 -0
- data/examples/weather-service/app/prompts/weather/chat.rb +90 -0
- data/examples/weather-service/app/resources/weather/alerts.rb +59 -0
- data/examples/weather-service/app/tools/weather/get_current.rb +82 -0
- data/examples/weather-service/app/tools/weather/get_forecast.rb +90 -0
- data/examples/weather-service/server.rb +28 -0
- data/exe/tsikol +6 -0
- data/lib/tsikol/cli/templates/Gemfile.erb +10 -0
- data/lib/tsikol/cli/templates/README.md.erb +38 -0
- data/lib/tsikol/cli/templates/gitignore.erb +49 -0
- data/lib/tsikol/cli/templates/prompt.rb.erb +53 -0
- data/lib/tsikol/cli/templates/resource.rb.erb +29 -0
- data/lib/tsikol/cli/templates/server.rb.erb +24 -0
- data/lib/tsikol/cli/templates/tool.rb.erb +60 -0
- data/lib/tsikol/cli.rb +203 -0
- data/lib/tsikol/error_handler.rb +141 -0
- data/lib/tsikol/health.rb +198 -0
- data/lib/tsikol/http_transport.rb +72 -0
- data/lib/tsikol/lifecycle.rb +149 -0
- data/lib/tsikol/middleware.rb +168 -0
- data/lib/tsikol/prompt.rb +101 -0
- data/lib/tsikol/resource.rb +53 -0
- data/lib/tsikol/router.rb +190 -0
- data/lib/tsikol/server.rb +660 -0
- data/lib/tsikol/stdio_transport.rb +108 -0
- data/lib/tsikol/test_helpers.rb +261 -0
- data/lib/tsikol/tool.rb +111 -0
- data/lib/tsikol/version.rb +5 -0
- data/lib/tsikol.rb +72 -0
- metadata +219 -0
@@ -0,0 +1,472 @@
|
|
1
|
+
# Completion Guide
|
2
|
+
|
3
|
+
Completion (autocomplete) provides intelligent suggestions for tool parameters and prompt arguments, enhancing the user experience.
|
4
|
+
|
5
|
+
## Table of Contents
|
6
|
+
|
7
|
+
1. [Overview](#overview)
|
8
|
+
2. [Basic Completion](#basic-completion)
|
9
|
+
3. [Dynamic Completion](#dynamic-completion)
|
10
|
+
4. [Advanced Patterns](#advanced-patterns)
|
11
|
+
5. [CLI Generation](#cli-generation)
|
12
|
+
6. [Best Practices](#best-practices)
|
13
|
+
|
14
|
+
## Overview
|
15
|
+
|
16
|
+
Completion helps users by:
|
17
|
+
- Suggesting valid values for parameters
|
18
|
+
- Reducing typing errors
|
19
|
+
- Improving discoverability
|
20
|
+
- Providing context-aware suggestions
|
21
|
+
|
22
|
+
## Basic Completion
|
23
|
+
|
24
|
+
### Tool Parameter Completion
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
class FileManager < Tsikol::Tool
|
28
|
+
description "Manage files in the project"
|
29
|
+
|
30
|
+
parameter :action do
|
31
|
+
type :string
|
32
|
+
required
|
33
|
+
description "Action to perform"
|
34
|
+
|
35
|
+
# Static completion
|
36
|
+
complete do |partial|
|
37
|
+
actions = ["create", "delete", "rename", "copy", "move"]
|
38
|
+
actions.select { |a| a.start_with?(partial.downcase) }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
parameter :file_type do
|
43
|
+
type :string
|
44
|
+
optional
|
45
|
+
description "Type of file"
|
46
|
+
|
47
|
+
# Filtered completion
|
48
|
+
complete do |partial|
|
49
|
+
types = ["ruby", "javascript", "python", "markdown", "json", "yaml"]
|
50
|
+
types.select { |t| t.include?(partial.downcase) }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def execute(action:, file_type: nil)
|
55
|
+
"Performing #{action} on #{file_type || 'all'} files"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
```
|
59
|
+
|
60
|
+
### Prompt Argument Completion
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
class CodeAssistant < Tsikol::Prompt
|
64
|
+
name "code_assistant"
|
65
|
+
description "AI coding assistant"
|
66
|
+
|
67
|
+
argument :language do
|
68
|
+
type :string
|
69
|
+
required
|
70
|
+
|
71
|
+
complete do |partial|
|
72
|
+
languages = [
|
73
|
+
"ruby", "python", "javascript", "typescript",
|
74
|
+
"go", "rust", "java", "c++", "swift"
|
75
|
+
]
|
76
|
+
languages.select { |lang| lang.start_with?(partial.downcase) }
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
argument :task do
|
81
|
+
type :string
|
82
|
+
required
|
83
|
+
|
84
|
+
complete do |partial|
|
85
|
+
tasks = [
|
86
|
+
"debug", "refactor", "optimize", "document",
|
87
|
+
"test", "review", "explain", "convert"
|
88
|
+
]
|
89
|
+
tasks.select { |task| task.include?(partial.downcase) }
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def get_messages(language:, task:)
|
94
|
+
[{
|
95
|
+
role: "user",
|
96
|
+
content: {
|
97
|
+
type: "text",
|
98
|
+
text: "Help me #{task} this #{language} code"
|
99
|
+
}
|
100
|
+
}]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
```
|
104
|
+
|
105
|
+
## Dynamic Completion
|
106
|
+
|
107
|
+
### File System Completion
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
class ProjectNavigator < Tsikol::Tool
|
111
|
+
description "Navigate project files"
|
112
|
+
|
113
|
+
parameter :path do
|
114
|
+
type :string
|
115
|
+
required
|
116
|
+
|
117
|
+
# Dynamic file system completion
|
118
|
+
complete do |partial|
|
119
|
+
# Expand home directory
|
120
|
+
expanded = partial.gsub('~', Dir.home)
|
121
|
+
|
122
|
+
# Get directory and file pattern
|
123
|
+
if expanded.include?('/')
|
124
|
+
dir = File.dirname(expanded)
|
125
|
+
pattern = File.basename(expanded)
|
126
|
+
else
|
127
|
+
dir = '.'
|
128
|
+
pattern = expanded
|
129
|
+
end
|
130
|
+
|
131
|
+
# Find matching files/directories
|
132
|
+
Dir.glob("#{dir}/#{pattern}*").map do |path|
|
133
|
+
# Add trailing slash for directories
|
134
|
+
File.directory?(path) ? "#{path}/" : path
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def execute(path:)
|
140
|
+
File.read(path)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
```
|
144
|
+
|
145
|
+
### Database-Driven Completion
|
146
|
+
|
147
|
+
```ruby
|
148
|
+
class DatabaseQuery < Tsikol::Tool
|
149
|
+
description "Query the database"
|
150
|
+
|
151
|
+
parameter :table do
|
152
|
+
type :string
|
153
|
+
required
|
154
|
+
|
155
|
+
# Complete from database schema
|
156
|
+
complete do |partial|
|
157
|
+
# In real app, query database for table names
|
158
|
+
tables = fetch_table_names
|
159
|
+
tables.select { |t| t.downcase.start_with?(partial.downcase) }
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
parameter :column do
|
164
|
+
type :string
|
165
|
+
optional
|
166
|
+
|
167
|
+
# Context-aware completion based on selected table
|
168
|
+
complete do |partial, context|
|
169
|
+
# Context contains previously entered parameters
|
170
|
+
table = context[:table]
|
171
|
+
return [] unless table
|
172
|
+
|
173
|
+
columns = fetch_columns_for_table(table)
|
174
|
+
columns.select { |c| c.downcase.include?(partial.downcase) }
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
private
|
179
|
+
|
180
|
+
def fetch_table_names
|
181
|
+
# Mock implementation
|
182
|
+
["users", "posts", "comments", "categories", "tags"]
|
183
|
+
end
|
184
|
+
|
185
|
+
def fetch_columns_for_table(table)
|
186
|
+
# Mock implementation
|
187
|
+
case table
|
188
|
+
when "users"
|
189
|
+
["id", "name", "email", "created_at", "updated_at"]
|
190
|
+
when "posts"
|
191
|
+
["id", "title", "content", "user_id", "published_at"]
|
192
|
+
else
|
193
|
+
["id", "created_at", "updated_at"]
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
```
|
198
|
+
|
199
|
+
## Advanced Patterns
|
200
|
+
|
201
|
+
### Hierarchical Completion
|
202
|
+
|
203
|
+
```ruby
|
204
|
+
class CloudManager < Tsikol::Tool
|
205
|
+
description "Manage cloud resources"
|
206
|
+
|
207
|
+
parameter :provider do
|
208
|
+
type :string
|
209
|
+
required
|
210
|
+
|
211
|
+
complete do |partial|
|
212
|
+
["aws", "gcp", "azure", "digitalocean"].select { |p|
|
213
|
+
p.start_with?(partial.downcase)
|
214
|
+
}
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
parameter :service do
|
219
|
+
type :string
|
220
|
+
required
|
221
|
+
|
222
|
+
# Completion depends on provider
|
223
|
+
complete do |partial, context|
|
224
|
+
services = case context[:provider]
|
225
|
+
when "aws"
|
226
|
+
["ec2", "s3", "lambda", "rds", "dynamodb"]
|
227
|
+
when "gcp"
|
228
|
+
["compute", "storage", "functions", "sql", "firestore"]
|
229
|
+
when "azure"
|
230
|
+
["vm", "blob", "functions", "sql", "cosmos"]
|
231
|
+
else
|
232
|
+
[]
|
233
|
+
end
|
234
|
+
|
235
|
+
services.select { |s| s.include?(partial.downcase) }
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
parameter :action do
|
240
|
+
type :string
|
241
|
+
required
|
242
|
+
|
243
|
+
# Multi-level context
|
244
|
+
complete do |partial, context|
|
245
|
+
actions = case [context[:provider], context[:service]]
|
246
|
+
when ["aws", "ec2"]
|
247
|
+
["start", "stop", "reboot", "terminate", "describe"]
|
248
|
+
when ["aws", "s3"]
|
249
|
+
["create-bucket", "delete-bucket", "upload", "download", "list"]
|
250
|
+
else
|
251
|
+
["list", "describe", "create", "delete"]
|
252
|
+
end
|
253
|
+
|
254
|
+
actions.select { |a| a.start_with?(partial.downcase) }
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
```
|
259
|
+
|
260
|
+
### Async Completion
|
261
|
+
|
262
|
+
```ruby
|
263
|
+
class APIClient < Tsikol::Tool
|
264
|
+
description "Call external APIs"
|
265
|
+
|
266
|
+
parameter :endpoint do
|
267
|
+
type :string
|
268
|
+
required
|
269
|
+
|
270
|
+
# Async completion from API
|
271
|
+
complete do |partial|
|
272
|
+
begin
|
273
|
+
# Cache results for performance
|
274
|
+
@endpoints_cache ||= fetch_available_endpoints
|
275
|
+
@endpoints_cache.select { |e| e.include?(partial) }
|
276
|
+
rescue => e
|
277
|
+
log :error, "Failed to fetch endpoints", data: { error: e.message }
|
278
|
+
[] # Return empty array on error
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
private
|
284
|
+
|
285
|
+
def fetch_available_endpoints
|
286
|
+
# In real app, this might call an API
|
287
|
+
[
|
288
|
+
"/api/v1/users",
|
289
|
+
"/api/v1/posts",
|
290
|
+
"/api/v1/comments",
|
291
|
+
"/api/v2/graphql"
|
292
|
+
]
|
293
|
+
end
|
294
|
+
end
|
295
|
+
```
|
296
|
+
|
297
|
+
### Fuzzy Matching Completion
|
298
|
+
|
299
|
+
```ruby
|
300
|
+
class CommandRunner < Tsikol::Tool
|
301
|
+
description "Run project commands"
|
302
|
+
|
303
|
+
parameter :command do
|
304
|
+
type :string
|
305
|
+
required
|
306
|
+
|
307
|
+
complete do |partial|
|
308
|
+
commands = [
|
309
|
+
"build:development",
|
310
|
+
"build:production",
|
311
|
+
"test:unit",
|
312
|
+
"test:integration",
|
313
|
+
"deploy:staging",
|
314
|
+
"deploy:production"
|
315
|
+
]
|
316
|
+
|
317
|
+
# Fuzzy matching
|
318
|
+
commands.select do |cmd|
|
319
|
+
# Match if all characters in partial appear in order
|
320
|
+
pattern = partial.chars.join('.*')
|
321
|
+
cmd.match?(/#{pattern}/i)
|
322
|
+
end.sort_by do |cmd|
|
323
|
+
# Sort by similarity
|
324
|
+
levenshtein_distance(partial.downcase, cmd.downcase)
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
private
|
330
|
+
|
331
|
+
def levenshtein_distance(s, t)
|
332
|
+
# Simple implementation
|
333
|
+
m = s.length
|
334
|
+
n = t.length
|
335
|
+
return m if n == 0
|
336
|
+
return n if m == 0
|
337
|
+
|
338
|
+
d = Array.new(m+1) { Array.new(n+1) }
|
339
|
+
|
340
|
+
(0..m).each { |i| d[i][0] = i }
|
341
|
+
(0..n).each { |j| d[0][j] = j }
|
342
|
+
|
343
|
+
(1..n).each do |j|
|
344
|
+
(1..m).each do |i|
|
345
|
+
cost = s[i-1] == t[j-1] ? 0 : 1
|
346
|
+
d[i][j] = [
|
347
|
+
d[i-1][j] + 1,
|
348
|
+
d[i][j-1] + 1,
|
349
|
+
d[i-1][j-1] + cost
|
350
|
+
].min
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
d[m][n]
|
355
|
+
end
|
356
|
+
end
|
357
|
+
```
|
358
|
+
|
359
|
+
## CLI Generation
|
360
|
+
|
361
|
+
When using the Tsikol CLI, completion hints are automatically added:
|
362
|
+
|
363
|
+
```bash
|
364
|
+
# Generate a tool with string parameters
|
365
|
+
tsikol g tool file_manager action:string path:string
|
366
|
+
|
367
|
+
# The generated file includes completion templates:
|
368
|
+
parameter :action do
|
369
|
+
type :string
|
370
|
+
required
|
371
|
+
description "TODO: Add description for action"
|
372
|
+
|
373
|
+
# Add completion for better UX
|
374
|
+
# complete do |partial|
|
375
|
+
# # Return array of possible values
|
376
|
+
# options = ["option1", "option2", "option3"]
|
377
|
+
# options.select { |opt| opt.start_with?(partial) }
|
378
|
+
# end
|
379
|
+
end
|
380
|
+
```
|
381
|
+
|
382
|
+
## Best Practices
|
383
|
+
|
384
|
+
### 1. Performance
|
385
|
+
|
386
|
+
```ruby
|
387
|
+
# Cache expensive operations
|
388
|
+
complete do |partial|
|
389
|
+
@cached_values ||= expensive_fetch_operation
|
390
|
+
@cached_values.select { |v| v.include?(partial) }
|
391
|
+
end
|
392
|
+
```
|
393
|
+
|
394
|
+
### 2. Error Handling
|
395
|
+
|
396
|
+
```ruby
|
397
|
+
complete do |partial|
|
398
|
+
begin
|
399
|
+
fetch_suggestions(partial)
|
400
|
+
rescue => e
|
401
|
+
log :error, "Completion failed", data: { error: e.message }
|
402
|
+
[] # Always return array
|
403
|
+
end
|
404
|
+
end
|
405
|
+
```
|
406
|
+
|
407
|
+
### 3. Limit Results
|
408
|
+
|
409
|
+
```ruby
|
410
|
+
complete do |partial|
|
411
|
+
all_suggestions = fetch_all_suggestions
|
412
|
+
filtered = all_suggestions.select { |s| s.include?(partial) }
|
413
|
+
filtered.first(20) # Limit to prevent UI overload
|
414
|
+
end
|
415
|
+
```
|
416
|
+
|
417
|
+
### 4. Context Awareness
|
418
|
+
|
419
|
+
```ruby
|
420
|
+
# Use context for dependent completions
|
421
|
+
complete do |partial, context|
|
422
|
+
# Access other parameter values
|
423
|
+
previous_value = context[:other_param]
|
424
|
+
|
425
|
+
suggestions_for(previous_value, partial)
|
426
|
+
end
|
427
|
+
```
|
428
|
+
|
429
|
+
### 5. User-Friendly Suggestions
|
430
|
+
|
431
|
+
```ruby
|
432
|
+
complete do |partial|
|
433
|
+
suggestions = fetch_suggestions
|
434
|
+
|
435
|
+
# Sort by relevance
|
436
|
+
exact_matches = suggestions.select { |s| s.start_with?(partial) }
|
437
|
+
partial_matches = suggestions.select { |s|
|
438
|
+
s.include?(partial) && !s.start_with?(partial)
|
439
|
+
}
|
440
|
+
|
441
|
+
# Exact matches first, then partial matches
|
442
|
+
(exact_matches + partial_matches).uniq
|
443
|
+
end
|
444
|
+
```
|
445
|
+
|
446
|
+
## Testing Completions
|
447
|
+
|
448
|
+
```ruby
|
449
|
+
require 'tsikol/test_helpers'
|
450
|
+
|
451
|
+
class CompletionTest < Minitest::Test
|
452
|
+
def test_tool_completion
|
453
|
+
client = Tsikol::TestHelpers::TestClient.new(server)
|
454
|
+
|
455
|
+
# Test completion
|
456
|
+
response = client.complete(
|
457
|
+
{ type: "ref/tool", name: "file_manager" },
|
458
|
+
{ name: "action", value: "cr" }
|
459
|
+
)
|
460
|
+
|
461
|
+
suggestions = response.dig(:result, :completion, :values)
|
462
|
+
assert_includes suggestions, "create"
|
463
|
+
assert_includes suggestions, "copy"
|
464
|
+
end
|
465
|
+
end
|
466
|
+
```
|
467
|
+
|
468
|
+
## Next Steps
|
469
|
+
|
470
|
+
- Learn about [Sampling](sampling.md) for AI assistance
|
471
|
+
- Explore [Advanced Features](../advanced-features.md)
|
472
|
+
- See [Complete Examples](../examples/)
|