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.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -0
  3. data/README.cn.md +305 -11
  4. data/README.md +309 -11
  5. data/Rakefile +10 -1
  6. data/config/anthropic_config.yml +151 -0
  7. data/config/image_generation_config.yml +22 -0
  8. data/config/multimodal_config.yml +85 -0
  9. data/config/sensenova_config.yml +63 -0
  10. data/config/zhipu_config.yml +73 -0
  11. data/docs/ANTHROPIC_EXAMPLES.md +559 -0
  12. data/docs/CONVERSATION_INTEGRATION_SUMMARY.md +155 -0
  13. data/docs/HISTORY_EXAMPLES_README.md +533 -0
  14. data/docs/HISTORY_MANAGEMENT_GUIDE.md +797 -0
  15. data/docs/MONITORING_GUIDE.md +278 -0
  16. data/docs/MULTIMODAL_README.md +265 -0
  17. data/docs/RELEVANCE_BASED_STRATEGY_IMPLEMENTATION.md +124 -0
  18. data/docs/STT_README.md +302 -0
  19. data/docs/TTS_README.md +303 -0
  20. data/docs/VIDEO_GENERATION_README.md +246 -0
  21. data/docs/delete_files_list.md +124 -0
  22. data/examples/anthropic_basic_chat.rb +143 -0
  23. data/examples/anthropic_example.rb +232 -0
  24. data/examples/anthropic_multimodal.rb +212 -0
  25. data/examples/anthropic_streaming.rb +312 -0
  26. data/examples/anthropic_tool_calling.rb +393 -0
  27. data/examples/automatic_cleanup_example.rb +109 -0
  28. data/examples/history_management_examples.rb +522 -0
  29. data/examples/image_generation_example.rb +130 -0
  30. data/examples/monitoring_example.rb +121 -0
  31. data/examples/multimodal_example.rb +63 -0
  32. data/examples/relevance_based_strategy_example.rb +87 -0
  33. data/examples/sensenova_example.rb +129 -0
  34. data/examples/stt_example.rb +287 -0
  35. data/examples/tts_example.rb +244 -0
  36. data/examples/video_generation_example.rb +189 -0
  37. data/examples/zhipu_example.rb +151 -0
  38. data/lib/smart_prompt/anthropic_adapter.rb +407 -298
  39. data/lib/smart_prompt/compression_engine.rb +201 -0
  40. data/lib/smart_prompt/context_strategy.rb +22 -0
  41. data/lib/smart_prompt/conversation.rb +47 -4
  42. data/lib/smart_prompt/engine.rb +29 -2
  43. data/lib/smart_prompt/history_manager.rb +596 -0
  44. data/lib/smart_prompt/hybrid_strategy.rb +222 -0
  45. data/lib/smart_prompt/image_generation_adapter.rb +297 -0
  46. data/lib/smart_prompt/lru_cache.rb +133 -0
  47. data/lib/smart_prompt/message.rb +57 -0
  48. data/lib/smart_prompt/multimodal_adapter.rb +277 -0
  49. data/lib/smart_prompt/persistence_layer.rb +197 -0
  50. data/lib/smart_prompt/relevance_based_strategy.rb +221 -0
  51. data/lib/smart_prompt/sensenova_adapter.rb +410 -0
  52. data/lib/smart_prompt/session.rb +140 -0
  53. data/lib/smart_prompt/sliding_window_strategy.rb +100 -0
  54. data/lib/smart_prompt/stt_adapter.rb +381 -0
  55. data/lib/smart_prompt/summary_based_strategy.rb +152 -0
  56. data/lib/smart_prompt/token_counter.rb +74 -0
  57. data/lib/smart_prompt/tts_adapter.rb +403 -0
  58. data/lib/smart_prompt/version.rb +1 -1
  59. data/lib/smart_prompt/video_generation_adapter.rb +330 -0
  60. data/lib/smart_prompt/worker.rb +28 -3
  61. data/lib/smart_prompt/zhipu_adapter.rb +616 -0
  62. data/lib/smart_prompt.rb +21 -0
  63. data/workers/history_management_examples.rb +407 -0
  64. data/workers/image_generation_workers.rb +119 -0
  65. data/workers/multimodal_workers.rb +110 -0
  66. data/workers/sensenova_workers.rb +62 -0
  67. data/workers/stt_workers.rb +195 -0
  68. data/workers/tts_workers.rb +388 -0
  69. data/workers/video_generation_workers.rb +264 -0
  70. data/workers/zhipu_workers.rb +113 -0
  71. metadata +88 -1
@@ -0,0 +1,63 @@
1
+ # SenseNova (商汤 日日新) Configuration for SmartPrompt
2
+ #
3
+ # Get an API key from https://platform.sensenova.cn/console and export it as
4
+ # SENSENOVA_API_KEY. A single SenseNovaAdapter covers all four model categories —
5
+ # just point a different llm entry at each model.
6
+ #
7
+ # Two base hosts are in play (verified 2026-06-19):
8
+ # * token.sensenova.cn/v1 — the free-tier models (sensenova-6.7-flash-lite
9
+ # chat/vision, sensenova-u1-fast image). Works
10
+ # out-of-the-box with a free key.
11
+ # * api.sensenova.cn/compatible-mode/v2 — paid models (SenseChat-5, SenseNova-V6-Pro).
12
+ # Returns 403 if your key lacks that model.
13
+ # * api.sensenova.cn/v1/llm/embeddings — Cupido embeddings (native; paid).
14
+ #
15
+ # The image endpoint is NOT under compatible-mode (it 404s there) — it lives on
16
+ # token.sensenova.cn/v1/images/generations and only accepts specific sizes
17
+ # (see VALID_IMAGE_SIZES in sensenova_adapter.rb; default 2048x2048).
18
+
19
+ adapters:
20
+ sensenova: "SenseNovaAdapter"
21
+
22
+ llms:
23
+ # 1. 商量 文本对话 (free-tier; works with a free key)
24
+ sensechat:
25
+ adapter: "sensenova"
26
+ url: "https://token.sensenova.cn/v1"
27
+ api_key: ENV["SENSENOVA_API_KEY"]
28
+ model: "sensenova-6.7-flash-lite"
29
+ temperature: 0.7
30
+ # Optional SenseNova sampling extras (forwarded to /chat/completions):
31
+ # reasoning_effort: "medium"
32
+ # max_completion_tokens: 4096
33
+ # Paid alternative: url https://api.sensenova.cn/compatible-mode/v2, model SenseChat-5
34
+
35
+ # 2. 商量 图文多模态 (sensenova-6.7-flash-lite is natively multimodal)
36
+ sensevision:
37
+ adapter: "sensenova"
38
+ url: "https://token.sensenova.cn/v1"
39
+ api_key: ENV["SENSENOVA_API_KEY"]
40
+ model: "sensenova-6.7-flash-lite"
41
+ # Paid alternative: url https://api.sensenova.cn/compatible-mode/v2, model SenseNova-V6-Pro
42
+
43
+ # 3. Cupido 向量模型 (paid; native endpoint, non-OpenAI response shape)
44
+ senseembedding:
45
+ adapter: "sensenova"
46
+ url: "https://api.sensenova.cn/compatible-mode/v2"
47
+ embeddings_url: "https://api.sensenova.cn/v1/llm/embeddings"
48
+ api_key: ENV["SENSENOVA_API_KEY"]
49
+ model: "Cupido"
50
+
51
+ # 4. 秒画 文生图 (free-tier sensenova-u1-fast; native token.sensenova.cn base)
52
+ senseimage:
53
+ adapter: "sensenova"
54
+ url: "https://token.sensenova.cn/v1"
55
+ image_url: "https://token.sensenova.cn/v1/images/generations"
56
+ api_key: ENV["SENSENOVA_API_KEY"]
57
+ model: "sensenova-u1-fast"
58
+
59
+ default_llm: "sensechat"
60
+
61
+ template_path: "./templates"
62
+ worker_path: "./workers"
63
+ logger_file: "./logs/smart_prompt.log"
@@ -0,0 +1,73 @@
1
+ # 智谱 AI (BigModel / GLM) Configuration for SmartPrompt
2
+ #
3
+ # Get an API key from https://open.bigmodel.cn/ and export it as ZHIPUAI_API_KEY.
4
+ # A single ZhipuAIAdapter covers all REST model categories — just point a different
5
+ # llm entry at each model. Defaults use the free-tier models so it runs out-of-box.
6
+ #
7
+ # Base URL: https://open.bigmodel.cn/api/paas/v4 (coding models: .../api/coding/paas/v4)
8
+ # Auth: Authorization: Bearer <API_KEY>
9
+
10
+ adapters:
11
+ zhipu: "ZhipuAIAdapter"
12
+
13
+ llms:
14
+ # 1. 文本对话 (free-tier glm-4-flash; paid: glm-4-plus / glm-4-long / glm-5.2)
15
+ glm:
16
+ adapter: "zhipu"
17
+ url: "https://open.bigmodel.cn/api/paas/v4"
18
+ api_key: ENV["ZHIPUAI_API_KEY"]
19
+ model: "glm-4-flash"
20
+ temperature: 0.7
21
+ # Optional sampling extras (forwarded to /chat/completions):
22
+ # top_p: 0.7
23
+ # max_tokens: 2048
24
+ # CodeGeeX-4: set `coding: true` (uses the coding base) and model: codegeex-4
25
+
26
+ # 2. 图文多模态 (free-tier glm-4v-flash; paid: glm-4v-plus)
27
+ glm_vision:
28
+ adapter: "zhipu"
29
+ url: "https://open.bigmodel.cn/api/paas/v4"
30
+ api_key: ENV["ZHIPUAI_API_KEY"]
31
+ model: "glm-4v-flash"
32
+
33
+ # 3. 向量模型 (embedding-3 supports custom dimensions: 256/512/1024/2048)
34
+ embedding:
35
+ adapter: "zhipu"
36
+ url: "https://open.bigmodel.cn/api/paas/v4"
37
+ api_key: ENV["ZHIPUAI_API_KEY"]
38
+ model: "embedding-3"
39
+ dimensions: 1024
40
+
41
+ # 4. 文生图 (free-tier cogview-3-flash; paid: cogview-4 / glm-image)
42
+ cogview:
43
+ adapter: "zhipu"
44
+ url: "https://open.bigmodel.cn/api/paas/v4"
45
+ api_key: ENV["ZHIPUAI_API_KEY"]
46
+ model: "cogview-3-flash"
47
+
48
+ # 5. 文生视频 (async: submit -> poll -> download; free-tier cogvideox-flash)
49
+ cogvideo:
50
+ adapter: "zhipu"
51
+ url: "https://open.bigmodel.cn/api/paas/v4"
52
+ api_key: ENV["ZHIPUAI_API_KEY"]
53
+ model: "cogvideox-flash"
54
+
55
+ # 6. 语音合成 (GLM-TTS)
56
+ glm_tts:
57
+ adapter: "zhipu"
58
+ url: "https://open.bigmodel.cn/api/paas/v4"
59
+ api_key: ENV["ZHIPUAI_API_KEY"]
60
+ model: "glm-tts"
61
+
62
+ # 7. 语音识别 (GLM-ASR-2512)
63
+ glm_asr:
64
+ adapter: "zhipu"
65
+ url: "https://open.bigmodel.cn/api/paas/v4"
66
+ api_key: ENV["ZHIPUAI_API_KEY"]
67
+ model: "glm-asr-2512"
68
+
69
+ default_llm: "glm"
70
+
71
+ template_path: "./templates"
72
+ worker_path: "./workers"
73
+ logger_file: "./logs/smart_prompt.log"
@@ -0,0 +1,559 @@
1
+ # Anthropic Claude Examples for SmartPrompt
2
+
3
+ This document provides comprehensive examples for using Anthropic's Claude models with SmartPrompt. Claude offers powerful capabilities including advanced reasoning, multimodal understanding (text + images), tool calling, and streaming responses.
4
+
5
+ ## Table of Contents
6
+
7
+ 1. [Setup and Configuration](#setup-and-configuration)
8
+ 2. [Basic Chat Examples](#basic-chat-examples)
9
+ 3. [Multimodal Examples (Vision)](#multimodal-examples-vision)
10
+ 4. [Tool Calling Examples](#tool-calling-examples)
11
+ 5. [Streaming Response Examples](#streaming-response-examples)
12
+ 6. [Advanced Usage](#advanced-usage)
13
+ 7. [Best Practices](#best-practices)
14
+
15
+ ## Setup and Configuration
16
+
17
+ ### 1. Install Dependencies
18
+
19
+ Ensure you have the `anthropic` gem installed:
20
+
21
+ ```ruby
22
+ gem 'anthropic', '~> 1.14'
23
+ ```
24
+
25
+ ### 2. Set API Key
26
+
27
+ Set your Anthropic API key as an environment variable:
28
+
29
+ ```bash
30
+ export ANTHROPIC_API_KEY='your-api-key-here'
31
+ ```
32
+
33
+ ### 3. Configure SmartPrompt
34
+
35
+ Create or update `config/anthropic_config.yml`:
36
+
37
+ ```yaml
38
+ adapters:
39
+ anthropic: "AnthropicAdapter"
40
+
41
+ llms:
42
+ claude:
43
+ adapter: "anthropic"
44
+ api_key: ENV["ANTHROPIC_API_KEY"]
45
+ model: "claude-3-5-sonnet-20241022"
46
+ temperature: 0.7
47
+ max_tokens: 4096
48
+
49
+ claude_haiku:
50
+ adapter: "anthropic"
51
+ api_key: ENV["ANTHROPIC_API_KEY"]
52
+ model: "claude-3-5-haiku-20241022"
53
+ temperature: 0.7
54
+ max_tokens: 4096
55
+
56
+ claude_opus:
57
+ adapter: "anthropic"
58
+ api_key: ENV["ANTHROPIC_API_KEY"]
59
+ model: "claude-3-opus-20240229"
60
+ temperature: 0.7
61
+ max_tokens: 4096
62
+ ```
63
+
64
+ ## Basic Chat Examples
65
+
66
+ ### Simple Question-Answer
67
+
68
+ ```ruby
69
+ require 'smart_prompt'
70
+
71
+ engine = SmartPrompt::Engine.new('config/anthropic_config.yml')
72
+
73
+ SmartPrompt.define_worker :simple_chat do
74
+ use "claude"
75
+ sys_msg("You are a helpful AI assistant.")
76
+ prompt(params[:message])
77
+ send_msg
78
+ end
79
+
80
+ response = engine.call_worker(:simple_chat, {
81
+ message: "What is the capital of France?"
82
+ })
83
+ puts response
84
+ ```
85
+
86
+ **Run the example:**
87
+ ```bash
88
+ ruby examples/anthropic_basic_chat.rb
89
+ ```
90
+
91
+ ### Multi-turn Conversation
92
+
93
+ ```ruby
94
+ SmartPrompt.define_worker :conversation do
95
+ use "claude"
96
+ sys_msg("You are a knowledgeable history teacher.")
97
+ prompt(params[:message], with_history: true)
98
+ send_msg
99
+ end
100
+
101
+ # First message
102
+ response1 = engine.call_worker(:conversation, {
103
+ message: "Who was the first president of the United States?"
104
+ })
105
+
106
+ # Follow-up message (maintains context)
107
+ response2 = engine.call_worker(:conversation, {
108
+ message: "What were his major accomplishments?"
109
+ })
110
+ ```
111
+
112
+ ### Using Different Models
113
+
114
+ ```ruby
115
+ # Claude 3.5 Sonnet - Best balance of intelligence and speed
116
+ SmartPrompt.define_worker :sonnet_chat do
117
+ use "claude"
118
+ model "claude-3-5-sonnet-20241022"
119
+ prompt(params[:message])
120
+ send_msg
121
+ end
122
+
123
+ # Claude 3.5 Haiku - Fastest, most cost-effective
124
+ SmartPrompt.define_worker :haiku_chat do
125
+ use "claude_haiku"
126
+ model "claude-3-5-haiku-20241022"
127
+ prompt(params[:message])
128
+ send_msg
129
+ end
130
+
131
+ # Claude 3 Opus - Highest quality for complex tasks
132
+ SmartPrompt.define_worker :opus_chat do
133
+ use "claude_opus"
134
+ model "claude-3-opus-20240229"
135
+ prompt(params[:message])
136
+ send_msg
137
+ end
138
+ ```
139
+
140
+ ### Temperature Control
141
+
142
+ ```ruby
143
+ # Creative writing (high temperature)
144
+ SmartPrompt.define_worker :creative_chat do
145
+ use "claude_creative" # temperature: 0.9
146
+ sys_msg("You are a creative writer.")
147
+ prompt("Write a creative tagline for a coffee shop.")
148
+ send_msg
149
+ end
150
+
151
+ # Precise analysis (low temperature)
152
+ SmartPrompt.define_worker :precise_chat do
153
+ use "claude_precise" # temperature: 0.3
154
+ sys_msg("You are a precise analyst.")
155
+ prompt("Analyze this data and provide key insights.")
156
+ send_msg
157
+ end
158
+ ```
159
+
160
+ ## Multimodal Examples (Vision)
161
+
162
+ Claude can analyze images alongside text. Supported formats: JPEG, PNG, GIF, WebP (up to 5MB).
163
+
164
+ ### Analyze Image from URL
165
+
166
+ ```ruby
167
+ SmartPrompt.define_worker :image_analyzer do
168
+ use "claude"
169
+ sys_msg("You are an expert at analyzing images.")
170
+ prompt(params[:message])
171
+ send_msg
172
+ end
173
+
174
+ response = engine.call_worker(:image_analyzer, {
175
+ message: [
176
+ { type: "text", text: "What do you see in this image?" },
177
+ { type: "image_url", image_url: "https://example.com/image.jpg" }
178
+ ]
179
+ })
180
+ ```
181
+
182
+ **Run the example:**
183
+ ```bash
184
+ ruby examples/anthropic_multimodal.rb
185
+ ```
186
+
187
+ ### Analyze Local Image (Base64)
188
+
189
+ ```ruby
190
+ require 'base64'
191
+
192
+ # Read and encode image
193
+ image_data = File.binread("./path/to/image.jpg")
194
+ base64_image = Base64.strict_encode64(image_data)
195
+ data_url = "data:image/jpeg;base64,#{base64_image}"
196
+
197
+ response = engine.call_worker(:image_analyzer, {
198
+ message: [
199
+ { type: "text", text: "Describe this image in detail." },
200
+ { type: "image_url", image_url: data_url }
201
+ ]
202
+ })
203
+ ```
204
+
205
+ ### Compare Multiple Images
206
+
207
+ ```ruby
208
+ response = engine.call_worker(:image_analyzer, {
209
+ message: [
210
+ { type: "text", text: "Compare these two images." },
211
+ { type: "image_url", image_url: "https://example.com/image1.jpg" },
212
+ { type: "image_url", image_url: "https://example.com/image2.jpg" }
213
+ ]
214
+ })
215
+ ```
216
+
217
+ ### OCR and Text Extraction
218
+
219
+ ```ruby
220
+ SmartPrompt.define_worker :ocr_extractor do
221
+ use "claude"
222
+ sys_msg("You are an expert at reading text from images.")
223
+ prompt(params[:message])
224
+ send_msg
225
+ end
226
+
227
+ response = engine.call_worker(:ocr_extractor, {
228
+ message: [
229
+ { type: "text", text: "Extract all text from this image." },
230
+ { type: "image_url", image_url: "https://example.com/document.jpg" }
231
+ ]
232
+ })
233
+ ```
234
+
235
+ ### Product Image Analysis
236
+
237
+ ```ruby
238
+ SmartPrompt.define_worker :product_analyzer do
239
+ use "claude"
240
+ sys_msg("You are a product analyst for e-commerce.")
241
+ prompt(params[:message])
242
+ send_msg
243
+ end
244
+
245
+ response = engine.call_worker(:product_analyzer, {
246
+ message: [
247
+ { type: "text", text: "Analyze this product image and provide:\n1. Product description\n2. Key features\n3. Suggested title" },
248
+ { type: "image_url", image_url: "https://example.com/product.jpg" }
249
+ ]
250
+ })
251
+ ```
252
+
253
+ ## Tool Calling Examples
254
+
255
+ Claude can use external tools/functions to perform actions or retrieve information.
256
+
257
+ ### Simple Weather Tool
258
+
259
+ ```ruby
260
+ weather_tool = [
261
+ {
262
+ type: "function",
263
+ function: {
264
+ name: "get_weather",
265
+ description: "Get the current weather for a location",
266
+ parameters: {
267
+ type: "object",
268
+ properties: {
269
+ location: {
270
+ type: "string",
271
+ description: "The city and state, e.g. San Francisco, CA"
272
+ },
273
+ unit: {
274
+ type: "string",
275
+ enum: ["celsius", "fahrenheit"],
276
+ description: "Temperature unit"
277
+ }
278
+ },
279
+ required: ["location"]
280
+ }
281
+ }
282
+ }
283
+ ]
284
+
285
+ SmartPrompt.define_worker :weather_assistant do
286
+ use "claude"
287
+ sys_msg("You are a weather assistant. Use the get_weather tool.")
288
+ prompt(params[:message])
289
+ params.merge(tools: weather_tool)
290
+ send_msg
291
+ end
292
+
293
+ response = engine.call_worker(:weather_assistant, {
294
+ message: "What's the weather in Tokyo?"
295
+ })
296
+ ```
297
+
298
+ **Run the example:**
299
+ ```bash
300
+ ruby examples/anthropic_tool_calling.rb
301
+ ```
302
+
303
+ ### Multiple Calculator Tools
304
+
305
+ ```ruby
306
+ calculator_tools = [
307
+ {
308
+ type: "function",
309
+ function: {
310
+ name: "add",
311
+ description: "Add two numbers",
312
+ parameters: {
313
+ type: "object",
314
+ properties: {
315
+ a: { type: "number" },
316
+ b: { type: "number" }
317
+ },
318
+ required: ["a", "b"]
319
+ }
320
+ }
321
+ },
322
+ {
323
+ type: "function",
324
+ function: {
325
+ name: "multiply",
326
+ description: "Multiply two numbers",
327
+ parameters: {
328
+ type: "object",
329
+ properties: {
330
+ a: { type: "number" },
331
+ b: { type: "number" }
332
+ },
333
+ required: ["a", "b"]
334
+ }
335
+ }
336
+ }
337
+ ]
338
+
339
+ SmartPrompt.define_worker :calculator do
340
+ use "claude"
341
+ sys_msg("You are a calculator assistant.")
342
+ prompt(params[:message])
343
+ params.merge(tools: calculator_tools)
344
+ send_msg
345
+ end
346
+ ```
347
+
348
+ ### Database Query Tool
349
+
350
+ ```ruby
351
+ database_tool = [
352
+ {
353
+ type: "function",
354
+ function: {
355
+ name: "query_database",
356
+ description: "Query the customer database",
357
+ parameters: {
358
+ type: "object",
359
+ properties: {
360
+ query_type: {
361
+ type: "string",
362
+ enum: ["customer_info", "order_history", "product_details"]
363
+ },
364
+ customer_id: { type: "string" }
365
+ },
366
+ required: ["query_type"]
367
+ }
368
+ }
369
+ }
370
+ ]
371
+ ```
372
+
373
+ ### Complex Tool with Nested Parameters
374
+
375
+ ```ruby
376
+ search_tool = [
377
+ {
378
+ type: "function",
379
+ function: {
380
+ name: "search_products",
381
+ description: "Search products with filters",
382
+ parameters: {
383
+ type: "object",
384
+ properties: {
385
+ query: { type: "string" },
386
+ filters: {
387
+ type: "object",
388
+ properties: {
389
+ category: { type: "string" },
390
+ price_range: {
391
+ type: "object",
392
+ properties: {
393
+ min: { type: "number" },
394
+ max: { type: "number" }
395
+ }
396
+ },
397
+ in_stock: { type: "boolean" }
398
+ }
399
+ },
400
+ sort_by: {
401
+ type: "string",
402
+ enum: ["price_asc", "price_desc", "popularity"]
403
+ }
404
+ },
405
+ required: ["query"]
406
+ }
407
+ }
408
+ }
409
+ ]
410
+ ```
411
+
412
+ ## Streaming Response Examples
413
+
414
+ Streaming provides better user experience by showing responses as they're generated.
415
+
416
+ ### Basic Streaming
417
+
418
+ ```ruby
419
+ SmartPrompt.define_worker :streaming_chat do
420
+ use "claude"
421
+ sys_msg("You are a helpful assistant.")
422
+ prompt(params[:message])
423
+ send_msg
424
+ end
425
+
426
+ engine.call_worker_by_stream(:streaming_chat, {
427
+ message: "Tell me a story about a brave knight."
428
+ }) do |chunk, bytesize|
429
+ if chunk.is_a?(Hash) && chunk["type"] == "content_block_delta"
430
+ text = chunk.dig("delta", "text")
431
+ print text if text
432
+ end
433
+ end
434
+ ```
435
+
436
+ **Run the example:**
437
+ ```bash
438
+ ruby examples/anthropic_streaming.rb
439
+ ```
440
+
441
+ ### Handling Different Event Types
442
+
443
+ ```ruby
444
+ engine.call_worker_by_stream(:streaming_chat, {
445
+ message: "Explain photosynthesis."
446
+ }) do |chunk, bytesize|
447
+ if chunk.is_a?(Hash)
448
+ case chunk["type"]
449
+ when "message_start"
450
+ # Message started
451
+ puts "[Starting response...]"
452
+ when "content_block_start"
453
+ # Content block started
454
+ when "content_block_delta"
455
+ # Incremental text
456
+ text = chunk.dig("delta", "text")
457
+ print text if text
458
+ when "content_block_stop"
459
+ # Content block finished
460
+ when "message_stop"
461
+ # Message complete
462
+ puts "\n[Response complete]"
463
+ end
464
+ end
465
+ end
466
+ ```
467
+
468
+ ### Streaming with Progress Tracking
469
+
470
+ ```ruby
471
+ char_count = 0
472
+
473
+ engine.call_worker_by_stream(:streaming_chat, {
474
+ message: "Write a Python function for Fibonacci."
475
+ }) do |chunk, bytesize|
476
+ if chunk.is_a?(Hash) && chunk["type"] == "content_block_delta"
477
+ text = chunk.dig("delta", "text")
478
+ if text
479
+ print text
480
+ char_count += text.length
481
+ end
482
+ end
483
+ end
484
+
485
+ puts "\n[Total characters: #{char_count}]"
486
+ ```
487
+
488
+ ### Streaming with Error Handling
489
+
490
+ ```ruby
491
+ begin
492
+ engine.call_worker_by_stream(:streaming_chat, {
493
+ message: "What are the benefits of exercise?"
494
+ }) do |chunk, bytesize|
495
+ if chunk.is_a?(Hash) && chunk["type"] == "content_block_delta"
496
+ text = chunk.dig("delta", "text")
497
+ print text if text
498
+ end
499
+ end
500
+ puts "\n[Stream completed successfully]"
501
+ rescue SmartPrompt::LLMAPIError => e
502
+ puts "\n[Error: #{e.message}]"
503
+ end
504
+ ```
505
+
506
+ ## Advanced Usage
507
+
508
+ ### Custom Endpoint (Proxy or Private Deployment)
509
+
510
+ ```yaml
511
+ llms:
512
+ claude_custom:
513
+ adapter: "anthropic"
514
+ api_key: ENV["ANTHROPIC_API_KEY"]
515
+ url: "https://your-custom-endpoint.com"
516
+ model: "claude-3-5-sonnet-20241022"
517
+ ```
518
+
519
+ ### Combining Multimodal and Tool Calling
520
+
521
+ ```ruby
522
+ tools = [
523
+ {
524
+ type: "function",
525
+ function: {
526
+ name: "identify_object",
527
+ description: "Identify objects in the image",
528
+ parameters: {
529
+ type: "object",
530
+ properties: {
531
+ object_name: { type: "string" }
532
+ },
533
+ required: ["object_name"]
534
+ }
535
+ }
536
+ }
537
+ ]
538
+
539
+ SmartPrompt.define_worker :multimodal_tools do
540
+ use "claude"
541
+ sys_msg("You can analyze images and use tools.")
542
+ prompt(params[:message])
543
+ params.merge(tools: tools)
544
+ send_msg
545
+ end
546
+
547
+ response = engine.call_worker(:multimodal_tools, {
548
+ message: [
549
+ { type: "text", text: "What objects do you see? Use the identify_object tool." },
550
+ { type: "image_url", image_url: "https://example.com/scene.jpg" }
551
+ ]
552
+ })
553
+ ```
554
+
555
+ ### Conversation with Mixed Content
556
+
557
+ ```ruby
558
+ SmartPrompt.define_worker :mixed_conversation do
559
+ use "cla