smart_prompt 0.4.4 → 0.5.1
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 +4 -4
- data/CHANGELOG.md +16 -0
- data/README.cn.md +305 -11
- data/README.md +309 -11
- data/Rakefile +10 -1
- data/config/anthropic_config.yml +151 -0
- data/config/image_generation_config.yml +22 -0
- data/config/multimodal_config.yml +85 -0
- data/config/sensenova_config.yml +63 -0
- data/config/zhipu_config.yml +73 -0
- data/docs/ANTHROPIC_EXAMPLES.md +559 -0
- data/docs/CONVERSATION_INTEGRATION_SUMMARY.md +155 -0
- data/docs/HISTORY_EXAMPLES_README.md +533 -0
- data/docs/HISTORY_MANAGEMENT_GUIDE.md +797 -0
- data/docs/MONITORING_GUIDE.md +278 -0
- data/docs/MULTIMODAL_README.md +265 -0
- data/docs/RELEVANCE_BASED_STRATEGY_IMPLEMENTATION.md +124 -0
- data/docs/STT_README.md +302 -0
- data/docs/TTS_README.md +303 -0
- data/docs/VIDEO_GENERATION_README.md +246 -0
- data/docs/delete_files_list.md +124 -0
- data/examples/anthropic_basic_chat.rb +143 -0
- data/examples/anthropic_example.rb +232 -0
- data/examples/anthropic_multimodal.rb +212 -0
- data/examples/anthropic_streaming.rb +312 -0
- data/examples/anthropic_tool_calling.rb +393 -0
- data/examples/automatic_cleanup_example.rb +109 -0
- data/examples/history_management_examples.rb +522 -0
- data/examples/image_generation_example.rb +130 -0
- data/examples/monitoring_example.rb +121 -0
- data/examples/multimodal_example.rb +63 -0
- data/examples/relevance_based_strategy_example.rb +87 -0
- data/examples/sensenova_example.rb +129 -0
- data/examples/stt_example.rb +287 -0
- data/examples/tts_example.rb +244 -0
- data/examples/video_generation_example.rb +189 -0
- data/examples/zhipu_example.rb +151 -0
- data/lib/smart_prompt/anthropic_adapter.rb +407 -298
- data/lib/smart_prompt/compression_engine.rb +201 -0
- data/lib/smart_prompt/context_strategy.rb +22 -0
- data/lib/smart_prompt/conversation.rb +47 -4
- data/lib/smart_prompt/engine.rb +29 -2
- data/lib/smart_prompt/history_manager.rb +596 -0
- data/lib/smart_prompt/hybrid_strategy.rb +222 -0
- data/lib/smart_prompt/image_generation_adapter.rb +297 -0
- data/lib/smart_prompt/lru_cache.rb +133 -0
- data/lib/smart_prompt/message.rb +57 -0
- data/lib/smart_prompt/multimodal_adapter.rb +277 -0
- data/lib/smart_prompt/persistence_layer.rb +197 -0
- data/lib/smart_prompt/relevance_based_strategy.rb +221 -0
- data/lib/smart_prompt/sensenova_adapter.rb +410 -0
- data/lib/smart_prompt/session.rb +140 -0
- data/lib/smart_prompt/sliding_window_strategy.rb +100 -0
- data/lib/smart_prompt/stt_adapter.rb +381 -0
- data/lib/smart_prompt/summary_based_strategy.rb +152 -0
- data/lib/smart_prompt/token_counter.rb +74 -0
- data/lib/smart_prompt/tts_adapter.rb +403 -0
- data/lib/smart_prompt/version.rb +1 -1
- data/lib/smart_prompt/video_generation_adapter.rb +330 -0
- data/lib/smart_prompt/worker.rb +28 -3
- data/lib/smart_prompt/zhipu_adapter.rb +616 -0
- data/lib/smart_prompt.rb +21 -0
- data/workers/history_management_examples.rb +407 -0
- data/workers/image_generation_workers.rb +119 -0
- data/workers/multimodal_workers.rb +110 -0
- data/workers/sensenova_workers.rb +62 -0
- data/workers/stt_workers.rb +195 -0
- data/workers/tts_workers.rb +388 -0
- data/workers/video_generation_workers.rb +264 -0
- data/workers/zhipu_workers.rb +113 -0
- metadata +88 -1
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require './lib/smart_prompt'
|
|
5
|
+
|
|
6
|
+
# Example: Streaming Responses with Anthropic Claude
|
|
7
|
+
# This example demonstrates how to use Claude's streaming capabilities
|
|
8
|
+
|
|
9
|
+
puts "=" * 60
|
|
10
|
+
puts "Anthropic Claude - Streaming Response Example"
|
|
11
|
+
puts "=" * 60
|
|
12
|
+
|
|
13
|
+
# Initialize the engine with Anthropic configuration
|
|
14
|
+
engine = SmartPrompt::Engine.new('config/anthropic_config.yml')
|
|
15
|
+
|
|
16
|
+
# Example 1: Basic Streaming
|
|
17
|
+
puts "\n1. Basic Streaming Response"
|
|
18
|
+
puts "-" * 60
|
|
19
|
+
|
|
20
|
+
SmartPrompt.define_worker :streaming_chat do
|
|
21
|
+
use "claude"
|
|
22
|
+
sys_msg("You are a helpful assistant.")
|
|
23
|
+
prompt(params[:message])
|
|
24
|
+
send_msg
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
print "User: Tell me a short story about a brave knight.\n"
|
|
28
|
+
print "Claude (streaming): "
|
|
29
|
+
|
|
30
|
+
engine.call_worker_by_stream(:streaming_chat, {
|
|
31
|
+
message: "Tell me a short story about a brave knight."
|
|
32
|
+
}) do |chunk, bytesize|
|
|
33
|
+
# Handle Anthropic streaming format
|
|
34
|
+
if chunk.is_a?(Hash)
|
|
35
|
+
if chunk["type"] == "content_block_delta"
|
|
36
|
+
text = chunk.dig("delta", "text")
|
|
37
|
+
print text if text
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
puts "\n"
|
|
43
|
+
|
|
44
|
+
# Example 2: Streaming with Different Event Types
|
|
45
|
+
puts "\n2. Streaming with Event Type Handling"
|
|
46
|
+
puts "-" * 60
|
|
47
|
+
|
|
48
|
+
SmartPrompt.define_worker :detailed_streaming do
|
|
49
|
+
use "claude"
|
|
50
|
+
sys_msg("You are a knowledgeable teacher.")
|
|
51
|
+
prompt(params[:message])
|
|
52
|
+
send_msg
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
print "User: Explain how photosynthesis works.\n"
|
|
56
|
+
print "Claude: "
|
|
57
|
+
|
|
58
|
+
message_started = false
|
|
59
|
+
content_started = false
|
|
60
|
+
|
|
61
|
+
engine.call_worker_by_stream(:detailed_streaming, {
|
|
62
|
+
message: "Explain how photosynthesis works in 3-4 sentences."
|
|
63
|
+
}) do |chunk, bytesize|
|
|
64
|
+
if chunk.is_a?(Hash)
|
|
65
|
+
case chunk["type"]
|
|
66
|
+
when "message_start"
|
|
67
|
+
message_started = true
|
|
68
|
+
# Message metadata available in chunk["message"]
|
|
69
|
+
when "content_block_start"
|
|
70
|
+
content_started = true
|
|
71
|
+
# Content block started
|
|
72
|
+
when "content_block_delta"
|
|
73
|
+
text = chunk.dig("delta", "text")
|
|
74
|
+
print text if text
|
|
75
|
+
when "content_block_stop"
|
|
76
|
+
# Content block finished
|
|
77
|
+
when "message_delta"
|
|
78
|
+
# Message metadata update (e.g., stop_reason)
|
|
79
|
+
when "message_stop"
|
|
80
|
+
# Message completely finished
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
puts "\n"
|
|
86
|
+
|
|
87
|
+
# Example 3: Streaming Long-form Content
|
|
88
|
+
puts "\n3. Streaming Long-form Content"
|
|
89
|
+
puts "-" * 60
|
|
90
|
+
|
|
91
|
+
SmartPrompt.define_worker :long_form_streaming do
|
|
92
|
+
use "claude"
|
|
93
|
+
sys_msg("You are a creative writer who writes engaging stories.")
|
|
94
|
+
prompt(params[:message])
|
|
95
|
+
send_msg
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
print "User: Write a detailed story about a robot learning to paint.\n"
|
|
99
|
+
print "Claude: "
|
|
100
|
+
|
|
101
|
+
total_chars = 0
|
|
102
|
+
|
|
103
|
+
engine.call_worker_by_stream(:long_form_streaming, {
|
|
104
|
+
message: "Write a detailed story (about 200 words) about a robot learning to paint."
|
|
105
|
+
}) do |chunk, bytesize|
|
|
106
|
+
if chunk.is_a?(Hash) && chunk["type"] == "content_block_delta"
|
|
107
|
+
text = chunk.dig("delta", "text")
|
|
108
|
+
if text
|
|
109
|
+
print text
|
|
110
|
+
total_chars += text.length
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
puts "\n\n[Total characters streamed: #{total_chars}]"
|
|
116
|
+
|
|
117
|
+
# Example 4: Streaming with Progress Indicator
|
|
118
|
+
puts "\n4. Streaming with Progress Indicator"
|
|
119
|
+
puts "-" * 60
|
|
120
|
+
|
|
121
|
+
SmartPrompt.define_worker :progress_streaming do
|
|
122
|
+
use "claude"
|
|
123
|
+
sys_msg("You are a helpful coding assistant.")
|
|
124
|
+
prompt(params[:message])
|
|
125
|
+
send_msg
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
print "User: Write a Python function to calculate Fibonacci numbers.\n"
|
|
129
|
+
print "Claude: "
|
|
130
|
+
|
|
131
|
+
char_count = 0
|
|
132
|
+
last_dot_time = Time.now
|
|
133
|
+
|
|
134
|
+
engine.call_worker_by_stream(:progress_streaming, {
|
|
135
|
+
message: "Write a Python function to calculate Fibonacci numbers with comments."
|
|
136
|
+
}) do |chunk, bytesize|
|
|
137
|
+
if chunk.is_a?(Hash) && chunk["type"] == "content_block_delta"
|
|
138
|
+
text = chunk.dig("delta", "text")
|
|
139
|
+
if text
|
|
140
|
+
print text
|
|
141
|
+
char_count += text.length
|
|
142
|
+
|
|
143
|
+
# Print a progress indicator every 50 characters
|
|
144
|
+
if char_count % 50 == 0 && Time.now - last_dot_time > 0.5
|
|
145
|
+
# This is just for demonstration
|
|
146
|
+
last_dot_time = Time.now
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
puts "\n"
|
|
153
|
+
|
|
154
|
+
# Example 5: Streaming with Error Handling
|
|
155
|
+
puts "\n5. Streaming with Error Handling"
|
|
156
|
+
puts "-" * 60
|
|
157
|
+
|
|
158
|
+
SmartPrompt.define_worker :safe_streaming do
|
|
159
|
+
use "claude"
|
|
160
|
+
sys_msg("You are a helpful assistant.")
|
|
161
|
+
prompt(params[:message])
|
|
162
|
+
send_msg
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
print "User: What are the benefits of exercise?\n"
|
|
166
|
+
print "Claude: "
|
|
167
|
+
|
|
168
|
+
begin
|
|
169
|
+
engine.call_worker_by_stream(:safe_streaming, {
|
|
170
|
+
message: "What are the benefits of exercise? List 5 benefits."
|
|
171
|
+
}) do |chunk, bytesize|
|
|
172
|
+
if chunk.is_a?(Hash) && chunk["type"] == "content_block_delta"
|
|
173
|
+
text = chunk.dig("delta", "text")
|
|
174
|
+
print text if text
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
puts "\n[Stream completed successfully]"
|
|
178
|
+
rescue SmartPrompt::LLMAPIError => e
|
|
179
|
+
puts "\n[Error during streaming: #{e.message}]"
|
|
180
|
+
rescue StandardError => e
|
|
181
|
+
puts "\n[Unexpected error: #{e.message}]"
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
puts ""
|
|
185
|
+
|
|
186
|
+
# Example 6: Streaming vs Non-Streaming Comparison
|
|
187
|
+
puts "\n6. Streaming vs Non-Streaming Comparison"
|
|
188
|
+
puts "-" * 60
|
|
189
|
+
|
|
190
|
+
question = "Explain the theory of relativity in simple terms."
|
|
191
|
+
|
|
192
|
+
# Non-streaming (traditional)
|
|
193
|
+
puts "Non-streaming mode:"
|
|
194
|
+
print "User: #{question}\n"
|
|
195
|
+
print "Claude: "
|
|
196
|
+
|
|
197
|
+
start_time = Time.now
|
|
198
|
+
|
|
199
|
+
SmartPrompt.define_worker :non_streaming_chat do
|
|
200
|
+
use "claude"
|
|
201
|
+
sys_msg("You are a physics teacher.")
|
|
202
|
+
prompt(params[:message])
|
|
203
|
+
send_msg
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
response = engine.call_worker(:non_streaming_chat, { message: question })
|
|
207
|
+
end_time = Time.now
|
|
208
|
+
|
|
209
|
+
puts response
|
|
210
|
+
puts "[Response received in #{(end_time - start_time).round(2)} seconds]\n"
|
|
211
|
+
|
|
212
|
+
# Streaming mode
|
|
213
|
+
puts "\nStreaming mode:"
|
|
214
|
+
print "User: #{question}\n"
|
|
215
|
+
print "Claude: "
|
|
216
|
+
|
|
217
|
+
start_time = Time.now
|
|
218
|
+
first_chunk_time = nil
|
|
219
|
+
|
|
220
|
+
SmartPrompt.define_worker :streaming_comparison do
|
|
221
|
+
use "claude"
|
|
222
|
+
sys_msg("You are a physics teacher.")
|
|
223
|
+
prompt(params[:message])
|
|
224
|
+
send_msg
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
engine.call_worker_by_stream(:streaming_comparison, { message: question }) do |chunk, bytesize|
|
|
228
|
+
if chunk.is_a?(Hash) && chunk["type"] == "content_block_delta"
|
|
229
|
+
first_chunk_time ||= Time.now
|
|
230
|
+
text = chunk.dig("delta", "text")
|
|
231
|
+
print text if text
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
end_time = Time.now
|
|
236
|
+
|
|
237
|
+
puts "\n[First chunk in #{(first_chunk_time - start_time).round(2)} seconds]"
|
|
238
|
+
puts "[Total time: #{(end_time - start_time).round(2)} seconds]\n"
|
|
239
|
+
|
|
240
|
+
# Example 7: Streaming with Different Models
|
|
241
|
+
puts "\n7. Streaming with Different Claude Models"
|
|
242
|
+
puts "-" * 60
|
|
243
|
+
|
|
244
|
+
question = "What is machine learning?"
|
|
245
|
+
|
|
246
|
+
# Claude 3.5 Sonnet
|
|
247
|
+
puts "Claude 3.5 Sonnet (streaming):"
|
|
248
|
+
print "User: #{question}\n"
|
|
249
|
+
print "Claude: "
|
|
250
|
+
|
|
251
|
+
SmartPrompt.define_worker :sonnet_streaming do
|
|
252
|
+
use "claude"
|
|
253
|
+
model "claude-3-5-sonnet-20241022"
|
|
254
|
+
prompt(params[:message])
|
|
255
|
+
send_msg
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
engine.call_worker_by_stream(:sonnet_streaming, { message: question }) do |chunk, bytesize|
|
|
259
|
+
if chunk.is_a?(Hash) && chunk["type"] == "content_block_delta"
|
|
260
|
+
text = chunk.dig("delta", "text")
|
|
261
|
+
print text if text
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
puts "\n"
|
|
266
|
+
|
|
267
|
+
# Claude 3.5 Haiku (faster)
|
|
268
|
+
puts "\nClaude 3.5 Haiku (streaming):"
|
|
269
|
+
print "User: #{question}\n"
|
|
270
|
+
print "Claude: "
|
|
271
|
+
|
|
272
|
+
SmartPrompt.define_worker :haiku_streaming do
|
|
273
|
+
use "claude_haiku"
|
|
274
|
+
model "claude-3-5-haiku-20241022"
|
|
275
|
+
prompt(params[:message])
|
|
276
|
+
send_msg
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
engine.call_worker_by_stream(:haiku_streaming, { message: question }) do |chunk, bytesize|
|
|
280
|
+
if chunk.is_a?(Hash) && chunk["type"] == "content_block_delta"
|
|
281
|
+
text = chunk.dig("delta", "text")
|
|
282
|
+
print text if text
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
puts "\n"
|
|
287
|
+
|
|
288
|
+
# Example 8: Streaming Best Practices
|
|
289
|
+
puts "\n8. Streaming Best Practices"
|
|
290
|
+
puts "-" * 60
|
|
291
|
+
|
|
292
|
+
puts "Best Practices for Streaming with Claude:"
|
|
293
|
+
puts "1. Use streaming for long-form content to improve perceived latency"
|
|
294
|
+
puts "2. Handle different event types appropriately:"
|
|
295
|
+
puts " - message_start: Initialize UI/state"
|
|
296
|
+
puts " - content_block_delta: Display incremental text"
|
|
297
|
+
puts " - message_stop: Finalize and clean up"
|
|
298
|
+
puts "3. Implement proper error handling for network issues"
|
|
299
|
+
puts "4. Consider buffering small chunks for smoother display"
|
|
300
|
+
puts "5. Show loading indicators before first chunk arrives"
|
|
301
|
+
puts "6. Use streaming for better user experience in chat applications"
|
|
302
|
+
puts "7. Non-streaming is better for short responses or batch processing"
|
|
303
|
+
puts "8. Test streaming behavior with different network conditions"
|
|
304
|
+
puts "9. Implement timeout handling for stalled streams"
|
|
305
|
+
puts "10. Consider token usage - streaming doesn't reduce costs\n"
|
|
306
|
+
|
|
307
|
+
puts "\n" + "=" * 60
|
|
308
|
+
puts "Streaming examples completed!"
|
|
309
|
+
puts "=" * 60
|
|
310
|
+
puts "\nNote: Streaming provides a better user experience by showing"
|
|
311
|
+
puts "responses as they're generated, reducing perceived latency."
|
|
312
|
+
puts "The total time and token usage is similar to non-streaming mode."
|
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require './lib/smart_prompt'
|
|
5
|
+
require 'json'
|
|
6
|
+
|
|
7
|
+
# Example: Tool Calling (Function Calling) with Anthropic Claude
|
|
8
|
+
# This example demonstrates how to use Claude with external tools/functions
|
|
9
|
+
|
|
10
|
+
puts "=" * 60
|
|
11
|
+
puts "Anthropic Claude - Tool Calling Example"
|
|
12
|
+
puts "=" * 60
|
|
13
|
+
|
|
14
|
+
# Initialize the engine with Anthropic configuration
|
|
15
|
+
engine = SmartPrompt::Engine.new('config/anthropic_config.yml')
|
|
16
|
+
|
|
17
|
+
# Example 1: Simple Weather Tool
|
|
18
|
+
puts "\n1. Simple Weather Tool"
|
|
19
|
+
puts "-" * 60
|
|
20
|
+
|
|
21
|
+
# Define the weather tool
|
|
22
|
+
weather_tool = [
|
|
23
|
+
{
|
|
24
|
+
type: "function",
|
|
25
|
+
function: {
|
|
26
|
+
name: "get_weather",
|
|
27
|
+
description: "Get the current weather for a specific location",
|
|
28
|
+
parameters: {
|
|
29
|
+
type: "object",
|
|
30
|
+
properties: {
|
|
31
|
+
location: {
|
|
32
|
+
type: "string",
|
|
33
|
+
description: "The city and state, e.g. San Francisco, CA"
|
|
34
|
+
},
|
|
35
|
+
unit: {
|
|
36
|
+
type: "string",
|
|
37
|
+
enum: ["celsius", "fahrenheit"],
|
|
38
|
+
description: "The temperature unit to use"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
required: ["location"]
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
SmartPrompt.define_worker :weather_assistant do
|
|
48
|
+
use "claude"
|
|
49
|
+
sys_msg("You are a helpful weather assistant. Use the get_weather tool when users ask about weather.")
|
|
50
|
+
prompt(params[:message])
|
|
51
|
+
params.merge(tools: weather_tool)
|
|
52
|
+
send_msg
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
response = engine.call_worker(:weather_assistant, {
|
|
56
|
+
message: "What's the weather like in Tokyo?"
|
|
57
|
+
})
|
|
58
|
+
puts "User: What's the weather like in Tokyo?"
|
|
59
|
+
puts "Claude: #{response}\n"
|
|
60
|
+
|
|
61
|
+
# Example 2: Multiple Tools - Calculator
|
|
62
|
+
puts "\n2. Calculator Tools"
|
|
63
|
+
puts "-" * 60
|
|
64
|
+
|
|
65
|
+
calculator_tools = [
|
|
66
|
+
{
|
|
67
|
+
type: "function",
|
|
68
|
+
function: {
|
|
69
|
+
name: "add",
|
|
70
|
+
description: "Add two numbers together",
|
|
71
|
+
parameters: {
|
|
72
|
+
type: "object",
|
|
73
|
+
properties: {
|
|
74
|
+
a: { type: "number", description: "First number" },
|
|
75
|
+
b: { type: "number", description: "Second number" }
|
|
76
|
+
},
|
|
77
|
+
required: ["a", "b"]
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
type: "function",
|
|
83
|
+
function: {
|
|
84
|
+
name: "multiply",
|
|
85
|
+
description: "Multiply two numbers",
|
|
86
|
+
parameters: {
|
|
87
|
+
type: "object",
|
|
88
|
+
properties: {
|
|
89
|
+
a: { type: "number", description: "First number" },
|
|
90
|
+
b: { type: "number", description: "Second number" }
|
|
91
|
+
},
|
|
92
|
+
required: ["a", "b"]
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
type: "function",
|
|
98
|
+
function: {
|
|
99
|
+
name: "divide",
|
|
100
|
+
description: "Divide two numbers",
|
|
101
|
+
parameters: {
|
|
102
|
+
type: "object",
|
|
103
|
+
properties: {
|
|
104
|
+
a: { type: "number", description: "Numerator" },
|
|
105
|
+
b: { type: "number", description: "Denominator" }
|
|
106
|
+
},
|
|
107
|
+
required: ["a", "b"]
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
SmartPrompt.define_worker :calculator_assistant do
|
|
114
|
+
use "claude"
|
|
115
|
+
sys_msg("You are a helpful calculator assistant. Use the available math tools to help users with calculations.")
|
|
116
|
+
prompt(params[:message])
|
|
117
|
+
params.merge(tools: calculator_tools)
|
|
118
|
+
send_msg
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
response = engine.call_worker(:calculator_assistant, {
|
|
122
|
+
message: "What is 15 multiplied by 23, then divided by 5?"
|
|
123
|
+
})
|
|
124
|
+
puts "User: What is 15 multiplied by 23, then divided by 5?"
|
|
125
|
+
puts "Claude: #{response}\n"
|
|
126
|
+
|
|
127
|
+
# Example 3: Database Query Tool
|
|
128
|
+
puts "\n3. Database Query Tool"
|
|
129
|
+
puts "-" * 60
|
|
130
|
+
|
|
131
|
+
database_tools = [
|
|
132
|
+
{
|
|
133
|
+
type: "function",
|
|
134
|
+
function: {
|
|
135
|
+
name: "query_database",
|
|
136
|
+
description: "Query the customer database for information",
|
|
137
|
+
parameters: {
|
|
138
|
+
type: "object",
|
|
139
|
+
properties: {
|
|
140
|
+
query_type: {
|
|
141
|
+
type: "string",
|
|
142
|
+
enum: ["customer_info", "order_history", "product_details"],
|
|
143
|
+
description: "The type of query to perform"
|
|
144
|
+
},
|
|
145
|
+
customer_id: {
|
|
146
|
+
type: "string",
|
|
147
|
+
description: "The customer ID to query"
|
|
148
|
+
},
|
|
149
|
+
filters: {
|
|
150
|
+
type: "object",
|
|
151
|
+
description: "Additional filters for the query"
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
required: ["query_type"]
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
]
|
|
159
|
+
|
|
160
|
+
SmartPrompt.define_worker :database_assistant do
|
|
161
|
+
use "claude"
|
|
162
|
+
sys_msg("You are a customer service assistant with access to the customer database. Use the query_database tool to help users.")
|
|
163
|
+
prompt(params[:message])
|
|
164
|
+
params.merge(tools: database_tools)
|
|
165
|
+
send_msg
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
response = engine.call_worker(:database_assistant, {
|
|
169
|
+
message: "Can you look up the order history for customer ID 12345?"
|
|
170
|
+
})
|
|
171
|
+
puts "User: Can you look up the order history for customer ID 12345?"
|
|
172
|
+
puts "Claude: #{response}\n"
|
|
173
|
+
|
|
174
|
+
# Example 4: File Operations Tool
|
|
175
|
+
puts "\n4. File Operations Tool"
|
|
176
|
+
puts "-" * 60
|
|
177
|
+
|
|
178
|
+
file_tools = [
|
|
179
|
+
{
|
|
180
|
+
type: "function",
|
|
181
|
+
function: {
|
|
182
|
+
name: "read_file",
|
|
183
|
+
description: "Read the contents of a file",
|
|
184
|
+
parameters: {
|
|
185
|
+
type: "object",
|
|
186
|
+
properties: {
|
|
187
|
+
file_path: {
|
|
188
|
+
type: "string",
|
|
189
|
+
description: "The path to the file to read"
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
required: ["file_path"]
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
type: "function",
|
|
198
|
+
function: {
|
|
199
|
+
name: "write_file",
|
|
200
|
+
description: "Write content to a file",
|
|
201
|
+
parameters: {
|
|
202
|
+
type: "object",
|
|
203
|
+
properties: {
|
|
204
|
+
file_path: {
|
|
205
|
+
type: "string",
|
|
206
|
+
description: "The path to the file to write"
|
|
207
|
+
},
|
|
208
|
+
content: {
|
|
209
|
+
type: "string",
|
|
210
|
+
description: "The content to write to the file"
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
required: ["file_path", "content"]
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
type: "function",
|
|
219
|
+
function: {
|
|
220
|
+
name: "list_files",
|
|
221
|
+
description: "List files in a directory",
|
|
222
|
+
parameters: {
|
|
223
|
+
type: "object",
|
|
224
|
+
properties: {
|
|
225
|
+
directory: {
|
|
226
|
+
type: "string",
|
|
227
|
+
description: "The directory path to list files from"
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
required: ["directory"]
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
]
|
|
235
|
+
|
|
236
|
+
SmartPrompt.define_worker :file_assistant do
|
|
237
|
+
use "claude"
|
|
238
|
+
sys_msg("You are a helpful file management assistant. Use the available file tools to help users manage their files.")
|
|
239
|
+
prompt(params[:message])
|
|
240
|
+
params.merge(tools: file_tools)
|
|
241
|
+
send_msg
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
response = engine.call_worker(:file_assistant, {
|
|
245
|
+
message: "Can you list all files in the /documents folder?"
|
|
246
|
+
})
|
|
247
|
+
puts "User: Can you list all files in the /documents folder?"
|
|
248
|
+
puts "Claude: #{response}\n"
|
|
249
|
+
|
|
250
|
+
# Example 5: API Integration Tool
|
|
251
|
+
puts "\n5. API Integration Tool"
|
|
252
|
+
puts "-" * 60
|
|
253
|
+
|
|
254
|
+
api_tools = [
|
|
255
|
+
{
|
|
256
|
+
type: "function",
|
|
257
|
+
function: {
|
|
258
|
+
name: "fetch_stock_price",
|
|
259
|
+
description: "Fetch the current stock price for a given ticker symbol",
|
|
260
|
+
parameters: {
|
|
261
|
+
type: "object",
|
|
262
|
+
properties: {
|
|
263
|
+
ticker: {
|
|
264
|
+
type: "string",
|
|
265
|
+
description: "The stock ticker symbol (e.g., AAPL, GOOGL)"
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
required: ["ticker"]
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
type: "function",
|
|
274
|
+
function: {
|
|
275
|
+
name: "fetch_news",
|
|
276
|
+
description: "Fetch recent news articles about a company or topic",
|
|
277
|
+
parameters: {
|
|
278
|
+
type: "object",
|
|
279
|
+
properties: {
|
|
280
|
+
query: {
|
|
281
|
+
type: "string",
|
|
282
|
+
description: "The search query for news articles"
|
|
283
|
+
},
|
|
284
|
+
limit: {
|
|
285
|
+
type: "number",
|
|
286
|
+
description: "Maximum number of articles to return"
|
|
287
|
+
}
|
|
288
|
+
},
|
|
289
|
+
required: ["query"]
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
]
|
|
294
|
+
|
|
295
|
+
SmartPrompt.define_worker :market_assistant do
|
|
296
|
+
use "claude"
|
|
297
|
+
sys_msg("You are a financial market assistant. Use the available tools to provide stock prices and news.")
|
|
298
|
+
prompt(params[:message])
|
|
299
|
+
params.merge(tools: api_tools)
|
|
300
|
+
send_msg
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
response = engine.call_worker(:market_assistant, {
|
|
304
|
+
message: "What's the current price of Apple stock and any recent news about the company?"
|
|
305
|
+
})
|
|
306
|
+
puts "User: What's the current price of Apple stock and any recent news about the company?"
|
|
307
|
+
puts "Claude: #{response}\n"
|
|
308
|
+
|
|
309
|
+
# Example 6: Complex Tool with Nested Parameters
|
|
310
|
+
puts "\n6. Complex Tool with Nested Parameters"
|
|
311
|
+
puts "-" * 60
|
|
312
|
+
|
|
313
|
+
search_tool = [
|
|
314
|
+
{
|
|
315
|
+
type: "function",
|
|
316
|
+
function: {
|
|
317
|
+
name: "search_products",
|
|
318
|
+
description: "Search for products in the catalog with advanced filters",
|
|
319
|
+
parameters: {
|
|
320
|
+
type: "object",
|
|
321
|
+
properties: {
|
|
322
|
+
query: {
|
|
323
|
+
type: "string",
|
|
324
|
+
description: "The search query"
|
|
325
|
+
},
|
|
326
|
+
filters: {
|
|
327
|
+
type: "object",
|
|
328
|
+
properties: {
|
|
329
|
+
category: {
|
|
330
|
+
type: "string",
|
|
331
|
+
description: "Product category"
|
|
332
|
+
},
|
|
333
|
+
price_range: {
|
|
334
|
+
type: "object",
|
|
335
|
+
properties: {
|
|
336
|
+
min: { type: "number", description: "Minimum price" },
|
|
337
|
+
max: { type: "number", description: "Maximum price" }
|
|
338
|
+
}
|
|
339
|
+
},
|
|
340
|
+
in_stock: {
|
|
341
|
+
type: "boolean",
|
|
342
|
+
description: "Only show in-stock items"
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
sort_by: {
|
|
347
|
+
type: "string",
|
|
348
|
+
enum: ["price_asc", "price_desc", "popularity", "newest"],
|
|
349
|
+
description: "How to sort the results"
|
|
350
|
+
}
|
|
351
|
+
},
|
|
352
|
+
required: ["query"]
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
]
|
|
357
|
+
|
|
358
|
+
SmartPrompt.define_worker :shopping_assistant do
|
|
359
|
+
use "claude"
|
|
360
|
+
sys_msg("You are a helpful shopping assistant. Use the search_products tool to help users find products.")
|
|
361
|
+
prompt(params[:message])
|
|
362
|
+
params.merge(tools: search_tool)
|
|
363
|
+
send_msg
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
response = engine.call_worker(:shopping_assistant, {
|
|
367
|
+
message: "Find me laptops under $1000 that are in stock, sorted by popularity"
|
|
368
|
+
})
|
|
369
|
+
puts "User: Find me laptops under $1000 that are in stock, sorted by popularity"
|
|
370
|
+
puts "Claude: #{response}\n"
|
|
371
|
+
|
|
372
|
+
# Example 7: Tool Calling Best Practices
|
|
373
|
+
puts "\n7. Tool Calling Best Practices"
|
|
374
|
+
puts "-" * 60
|
|
375
|
+
|
|
376
|
+
puts "Best Practices for Tool Calling with Claude:"
|
|
377
|
+
puts "1. Provide clear, descriptive function names"
|
|
378
|
+
puts "2. Write detailed descriptions for functions and parameters"
|
|
379
|
+
puts "3. Use appropriate parameter types (string, number, boolean, object, array)"
|
|
380
|
+
puts "4. Mark required parameters explicitly"
|
|
381
|
+
puts "5. Use enums for parameters with limited valid values"
|
|
382
|
+
puts "6. Include examples in parameter descriptions when helpful"
|
|
383
|
+
puts "7. Keep tool definitions focused and single-purpose"
|
|
384
|
+
puts "8. Test tools with various user queries"
|
|
385
|
+
puts "9. Handle tool errors gracefully in your implementation"
|
|
386
|
+
puts "10. Consider tool execution order for complex workflows\n"
|
|
387
|
+
|
|
388
|
+
puts "\n" + "=" * 60
|
|
389
|
+
puts "Tool calling examples completed!"
|
|
390
|
+
puts "=" * 60
|
|
391
|
+
puts "\nNote: These examples show tool definitions. In a real application,"
|
|
392
|
+
puts "you would implement the actual tool functions and handle the tool"
|
|
393
|
+
puts "calls returned by Claude to execute the requested operations."
|