scout-ai 1.2.3 → 2.0.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 +4 -4
- data/.vimproject +138 -50
- data/README.md +171 -290
- data/Rakefile +17 -1
- data/VERSION +1 -1
- data/doc/Improvements.md +325 -0
- data/doc/StartHere.md +110 -0
- data/doc/developer/Architecture.md +126 -0
- data/doc/developer/Backends.md +199 -0
- data/doc/developer/ChatLifecycle.md +183 -0
- data/doc/developer/DelegationInternals.md +295 -0
- data/doc/developer/DesignPrinciples.md +245 -0
- data/doc/developer/PromptProcessing.md +292 -0
- data/doc/developer/Provenance.md +317 -0
- data/doc/user/BuildingAgents.md +345 -0
- data/doc/user/Cookbook.md +333 -0
- data/doc/user/CoreConcepts.md +181 -0
- data/doc/user/Delegation.md +191 -0
- data/doc/user/GettingStarted.md +159 -0
- data/doc/user/ManagingContext.md +163 -0
- data/doc/user/MultiAgentWorkflows.md +256 -0
- data/doc/user/Python.md +159 -0
- data/doc/user/RunningInference.md +200 -0
- data/doc/user/ToolCalling.md +193 -0
- data/doc/user/WritingChats.md +197 -0
- data/lib/scout/llm/agent/chat.rb +61 -11
- data/lib/scout/llm/agent/delegate.rb +274 -65
- data/lib/scout/llm/agent/iterate.rb +2 -2
- data/lib/scout/llm/agent/save.rb +273 -0
- data/lib/scout/llm/agent/workflow.rb +164 -0
- data/lib/scout/llm/agent.rb +86 -61
- data/lib/scout/llm/ask.rb +62 -17
- data/lib/scout/llm/backends/anthropic.rb +9 -2
- data/lib/scout/llm/backends/bedrock.rb +15 -3
- data/lib/scout/llm/backends/default.rb +183 -99
- data/lib/scout/llm/backends/glm.rb +58 -0
- data/lib/scout/llm/backends/huggingface.rb +196 -26
- data/lib/scout/llm/backends/ollama.rb +13 -1
- data/lib/scout/llm/backends/openai.rb +0 -2
- data/lib/scout/llm/backends/openwebui.rb +20 -13
- data/lib/scout/llm/backends/relay.rb +22 -22
- data/lib/scout/llm/backends/responses.rb +1 -1
- data/lib/scout/llm/chat/agent_meta.rb +264 -0
- data/lib/scout/llm/chat/annotation.rb +39 -10
- data/lib/scout/llm/chat/parse.rb +28 -6
- data/lib/scout/llm/chat/persist.rb +25 -0
- data/lib/scout/llm/chat/process/clear.rb +41 -6
- data/lib/scout/llm/chat/process/files.rb +21 -6
- data/lib/scout/llm/chat/process/meta.rb +421 -34
- data/lib/scout/llm/chat/process/options.rb +21 -1
- data/lib/scout/llm/chat/process/tools.rb +56 -15
- data/lib/scout/llm/chat/process.rb +4 -0
- data/lib/scout/llm/chat/prompt/shorten_tools.rb +125 -0
- data/lib/scout/llm/chat/prompt/shorten_tools_epoch.rb +365 -0
- data/lib/scout/llm/chat/prompt.rb +48 -0
- data/lib/scout/llm/chat/provenance.rb +775 -0
- data/lib/scout/llm/chat/tool_calls.rb +76 -0
- data/lib/scout/llm/chat.rb +18 -2
- data/lib/scout/llm/embed.rb +11 -3
- data/lib/scout/llm/image.rb +86 -0
- data/lib/scout/llm/mcp.rb +10 -2
- data/lib/scout/llm/rag.rb +3 -3
- data/lib/scout/llm/tools/call.rb +160 -11
- data/lib/scout/llm/tools/knowledge_base.rb +1 -1
- data/lib/scout/llm/tools/workflow.rb +32 -16
- data/lib/scout/model/python/huggingface/causal.rb +23 -5
- data/lib/scout/model/python/huggingface.rb +2 -1
- data/lib/scout-ai.rb +1 -0
- data/python/README.md +197 -14
- data/python/scout_ai/huggingface/eval.py +245 -34
- data/python/tests/test_huggingface_eval.py +58 -0
- data/research/ChatAnalyst-required-changes.md +167 -0
- data/research/agent-delegation-analysis.md +810 -0
- data/research/agent-meta-provenance-integration-plan.md +622 -0
- data/research/agent-workflow-analysis.md +1120 -0
- data/research/backends-analysis.md +836 -0
- data/research/chat-core-analysis.md +946 -0
- data/research/chatanalyst-provenance/00-baseline.md +30 -0
- data/research/chatanalyst-provenance/01-repo-map.md +60 -0
- data/research/chatanalyst-provenance/02-event-reconstruction.md +55 -0
- data/research/chatanalyst-provenance/03-duplication-evidence.md +45 -0
- data/research/chatanalyst-provenance/04-tooling-root-cause.md +57 -0
- data/research/chatanalyst-provenance/05-fix-plan.md +46 -0
- data/research/chatanalyst-provenance/07-critic-review.md +25 -0
- data/research/chatanalyst-provenance/final-report.md +45 -0
- data/research/chatanalyst-provenance/resumption.md +37 -0
- data/research/coding-philosophy-analysis.md +928 -0
- data/research/commands-analysis.md +947 -0
- data/research/multi-agent-patterns-analysis.md +853 -0
- data/research/prompt-strategies-analysis.md +630 -0
- data/research/prov-verbosity-fix-notes.md +77 -0
- data/research/provenance-analysis.md +469 -0
- data/research/provenance-navigation-design.md +640 -0
- data/research/synthesis-report.md +487 -0
- data/research/tools-system-analysis.md +779 -0
- data/scout-ai.gemspec +100 -11
- data/scout_commands/agent/ask +13 -3
- data/scout_commands/agent/kb +2 -0
- data/scout_commands/llm/ask +11 -4
- data/scout_commands/llm/md +76 -0
- data/scout_commands/llm/process_queries +48 -0
- data/scout_commands/llm/prov +602 -0
- data/scout_commands/llm/word +71 -0
- data/scout_commands/workflow/mcp +43 -0
- data/share/word/reference.docx +0 -0
- data/test/etc/AI/mock.yaml +11 -0
- data/test/fixtures/backends/anthropic.json +19 -0
- data/test/fixtures/backends/anthropic_tool_use.json +24 -0
- data/test/fixtures/backends/bedrock.json +8 -0
- data/test/fixtures/backends/bedrock_embedding.json +3 -0
- data/test/fixtures/backends/bedrock_tool_use.json +17 -0
- data/test/fixtures/backends/ollama.json +16 -0
- data/test/fixtures/backends/ollama_tool_call.json +27 -0
- data/test/fixtures/backends/openai_chat.json +21 -0
- data/test/fixtures/backends/openai_chat_tool_call.json +31 -0
- data/test/fixtures/backends/responses.json +33 -0
- data/test/fixtures/backends/responses_tool_call.json +28 -0
- data/test/integration/README.md +32 -0
- data/test/integration/scout/llm/backends/test_endpoints.rb +34 -0
- data/test/integration/scout/llm/backends/test_openwebui.rb +61 -0
- data/test/integration/scout/llm/backends/test_relay.rb +52 -0
- data/test/integration/scout/llm/test_infrastructure.rb +74 -0
- data/test/{scout → integration/scout}/llm/test_mcp.rb +1 -1
- data/test/integration/scout/llm/tools/test_mcp.rb +42 -0
- data/test/integration/scout/model/test_base.rb +91 -0
- data/test/scout/llm/agent/test_chat.rb +8 -2
- data/test/scout/llm/agent/test_save.rb +413 -0
- data/test/scout/llm/agent/test_workflow.rb +110 -0
- data/test/scout/llm/backends/test_anthropic.rb +93 -10
- data/test/scout/llm/backends/test_bedrock.rb +118 -2
- data/test/scout/llm/backends/test_huggingface.rb +137 -42
- data/test/scout/llm/backends/test_ollama.rb +70 -20
- data/test/scout/llm/backends/test_openwebui.rb +42 -40
- data/test/scout/llm/backends/test_relay.rb +4 -2
- data/test/scout/llm/chat/agent_meta_fixtures.rb +131 -0
- data/test/scout/llm/chat/process/test_meta.rb +518 -0
- data/test/scout/llm/chat/process/test_normalize_usage.rb +183 -0
- data/test/scout/llm/chat/test_agent_meta.rb +357 -0
- data/test/scout/llm/chat/test_agent_meta_provenance.rb +467 -0
- data/test/scout/llm/chat/test_agent_meta_tokens.rb +594 -0
- data/test/scout/llm/chat/test_parse.rb +70 -15
- data/test/scout/llm/chat/test_prov_cli.rb +274 -0
- data/test/scout/llm/chat/test_provenance.rb +240 -0
- data/test/scout/llm/chat/test_tool_calls.rb +38 -0
- data/test/scout/llm/test_agent.rb +13 -36
- data/test/scout/llm/test_ask.rb +75 -52
- data/test/scout/llm/test_chat.rb +107 -13
- data/test/scout/llm/test_embed.rb +48 -0
- data/test/scout/llm/test_rag.rb +23 -16
- data/test/scout/llm/test_tools.rb +12 -1
- data/test/scout/llm/tools/test_knowledge_base.rb +0 -1
- data/test/scout/llm/tools/test_mcp.rb +5 -3
- data/test/scout/llm/tools/test_workflow.rb +23 -2
- data/test/scout/model/python/huggingface/causal/test_next_token.rb +11 -5
- data/test/scout/model/python/huggingface/test_causal.rb +9 -3
- data/test/scout/model/python/huggingface/test_classification.rb +11 -2
- data/test/scout/model/python/test_torch.rb +2 -0
- data/test/scout/model/python/torch/test_helpers.rb +4 -0
- data/test/scout/model/test_base.rb +4 -2
- data/test/support/availability.rb +231 -0
- data/test/support/fake_clients.rb +138 -0
- data/test/support/fixtures.rb +21 -0
- data/test/support/infrastructure_probes.rb +136 -0
- data/test/support/mock_backend.rb +215 -0
- data/test/test_helper.rb +32 -2
- metadata +99 -10
- data/doc/Agent.md +0 -327
- data/doc/Chat.md +0 -458
- data/doc/LLM.md +0 -340
- data/doc/RAG.md +0 -129
- data/scout_commands/documenter +0 -148
- data/test/scout/llm/backends/test_openai.rb +0 -192
- data/test/scout/llm/backends/test_responses.rb +0 -238
- data/test/scout/llm/test_parse.rb +0 -98
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
require File.expand_path(__FILE__).sub(%r(/test/.*), '/test/test_helper.rb')
|
|
2
|
-
require File.expand_path(__FILE__).sub(%r(.*/test/), '').sub(/test_(.*)\.rb/,'\1')
|
|
3
|
-
|
|
4
|
-
class TestLLMOpenAI < Test::Unit::TestCase
|
|
5
|
-
def test_ask
|
|
6
|
-
prompt =<<-EOF
|
|
7
|
-
system: you are a coding helper that only write code and comments without formatting so that it can work directly, avoid the initial and end commas ```.
|
|
8
|
-
user: write a script that sorts files in a directory
|
|
9
|
-
EOF
|
|
10
|
-
sss 0
|
|
11
|
-
ppp LLM::OpenAI.ask prompt
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def _test_embeddings
|
|
15
|
-
Log.severity = 0
|
|
16
|
-
text =<<-EOF
|
|
17
|
-
Some text
|
|
18
|
-
EOF
|
|
19
|
-
emb = LLM::OpenAI.embed text, log_errors: true, model: 'embedding-model'
|
|
20
|
-
|
|
21
|
-
assert(Float === emb.first)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def _test_tool_call_output
|
|
25
|
-
Log.severity = 0
|
|
26
|
-
prompt =<<-EOF
|
|
27
|
-
function_call:
|
|
28
|
-
|
|
29
|
-
{"type":"function","function":{"name":"Baking-bake_muffin_tray","arguments":"{}"},"id":"Baking_bake_muffin_tray_Default"}
|
|
30
|
-
|
|
31
|
-
function_call_output:
|
|
32
|
-
|
|
33
|
-
{"id":"Baking_bake_muffin_tray_Default","role":"tool","content":"Baking batter (Mixing base (Whisking eggs from share/pantry/eggs) with mixer (share/pantry/flour))"}
|
|
34
|
-
|
|
35
|
-
user:
|
|
36
|
-
|
|
37
|
-
How do you bake muffins, according to the tool I provided you. Don't
|
|
38
|
-
tell me the recipe you already know, use the tool call output. Let me
|
|
39
|
-
know if you didn't get it.
|
|
40
|
-
EOF
|
|
41
|
-
ppp LLM::OpenAI.ask prompt, model: 'gpt-4.1-nano'
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def _test_tool_call_output_2
|
|
45
|
-
Log.severity = 0
|
|
46
|
-
prompt =<<-EOF
|
|
47
|
-
function_call:
|
|
48
|
-
|
|
49
|
-
{"name":"get_current_temperature", "arguments":{"location":"London","unit":"Celsius"},"id":"tNTnsQq2s6jGh0npOh43AwDD"}
|
|
50
|
-
|
|
51
|
-
function_call_output:
|
|
52
|
-
|
|
53
|
-
{"id":"tNTnsQq2s6jGh0npOh43AwDD", "content":"It's 15 degrees and raining."}
|
|
54
|
-
|
|
55
|
-
user:
|
|
56
|
-
|
|
57
|
-
should i take an umbrella?
|
|
58
|
-
EOF
|
|
59
|
-
ppp LLM::OpenAI.ask prompt, model: 'gpt-4.1-nano'
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def _test_tool_call_output_features
|
|
63
|
-
Log.severity = 0
|
|
64
|
-
prompt =<<-EOF
|
|
65
|
-
function_call:
|
|
66
|
-
|
|
67
|
-
{"name":"Baking-bake_muffin_tray","arguments":{},"id":"Baking_bake_muffin_tray_Default"}
|
|
68
|
-
|
|
69
|
-
function_call_output:
|
|
70
|
-
|
|
71
|
-
{"id":"Baking_bake_muffin_tray_Default","content":"Baking batter (Mixing base (Whisking eggs from share/pantry/eggs) with mixer (share/pantry/flour))"}
|
|
72
|
-
|
|
73
|
-
user:
|
|
74
|
-
|
|
75
|
-
How do you bake muffins, according to the tool I provided you. Don't
|
|
76
|
-
tell me the recipe you already know, use the tool call output. Let me
|
|
77
|
-
know if you didn't get it.
|
|
78
|
-
EOF
|
|
79
|
-
ppp LLM::OpenAI.ask prompt, model: 'gpt-4.1-nano'
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def _test_tool_call_output_weather
|
|
83
|
-
Log.severity = 0
|
|
84
|
-
prompt =<<-EOF
|
|
85
|
-
function_call:
|
|
86
|
-
|
|
87
|
-
{"name":"get_current_temperature", "arguments":{"location":"London","unit":"Celsius"},"id":"tNTnsQq2s6jGh0npOh43AwDD"}
|
|
88
|
-
|
|
89
|
-
function_call_output:
|
|
90
|
-
|
|
91
|
-
{"id":"tNTnsQq2s6jGh0npOh43AwDD", "content":"It's 15 degrees and raining."}
|
|
92
|
-
|
|
93
|
-
user:
|
|
94
|
-
|
|
95
|
-
should i take an umbrella?
|
|
96
|
-
EOF
|
|
97
|
-
ppp LLM::OpenAI.ask prompt, model: 'gpt-4.1-nano'
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
def _test_tool_gpt5
|
|
102
|
-
prompt =<<-EOF
|
|
103
|
-
user:
|
|
104
|
-
What is the weather in London. Should I take my umbrella?
|
|
105
|
-
EOF
|
|
106
|
-
|
|
107
|
-
tools = [
|
|
108
|
-
{
|
|
109
|
-
"type": "function",
|
|
110
|
-
"function": {
|
|
111
|
-
"name": "get_current_temperature",
|
|
112
|
-
"description": "Get the current temperature and raining conditions for a specific location",
|
|
113
|
-
"parameters": {
|
|
114
|
-
"type": "object",
|
|
115
|
-
"properties": {
|
|
116
|
-
"location": {
|
|
117
|
-
"type": "string",
|
|
118
|
-
"description": "The city and state, e.g., San Francisco, CA"
|
|
119
|
-
},
|
|
120
|
-
"unit": {
|
|
121
|
-
"type": "string",
|
|
122
|
-
"enum": ["Celsius", "Fahrenheit"],
|
|
123
|
-
"description": "The temperature unit to use. Infer this from the user's location."
|
|
124
|
-
}
|
|
125
|
-
},
|
|
126
|
-
"required": ["location", "unit"]
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
},
|
|
130
|
-
]
|
|
131
|
-
|
|
132
|
-
respose = LLM::OpenAI.ask prompt, tool_choice: 'required', tools: tools, model: "gpt-5", log_errors: true do |name,arguments|
|
|
133
|
-
"It's 15 degrees and raining."
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
ppp respose
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
def _test_tool
|
|
140
|
-
prompt =<<-EOF
|
|
141
|
-
user:
|
|
142
|
-
What is the weather in London. Should I take my umbrella?
|
|
143
|
-
EOF
|
|
144
|
-
|
|
145
|
-
tools = [
|
|
146
|
-
{
|
|
147
|
-
"type": "function",
|
|
148
|
-
"function": {
|
|
149
|
-
"name": "get_current_temperature",
|
|
150
|
-
"description": "Get the current temperature and raining conditions for a specific location",
|
|
151
|
-
"parameters": {
|
|
152
|
-
"type": "object",
|
|
153
|
-
"properties": {
|
|
154
|
-
"location": {
|
|
155
|
-
"type": "string",
|
|
156
|
-
"description": "The city and state, e.g., San Francisco, CA"
|
|
157
|
-
},
|
|
158
|
-
"unit": {
|
|
159
|
-
"type": "string",
|
|
160
|
-
"enum": ["Celsius", "Fahrenheit"],
|
|
161
|
-
"description": "The temperature unit to use. Infer this from the user's location."
|
|
162
|
-
}
|
|
163
|
-
},
|
|
164
|
-
"required": ["location", "unit"]
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
},
|
|
168
|
-
]
|
|
169
|
-
|
|
170
|
-
sss 0
|
|
171
|
-
respose = LLM::OpenAI.ask prompt, tool_choice: 'required', tools: tools, model: "gpt-4.1-mini", log_errors: true do |name,arguments|
|
|
172
|
-
"It's 15 degrees and raining."
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
ppp respose
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
def _test_json_output
|
|
179
|
-
prompt =<<-EOF
|
|
180
|
-
system:
|
|
181
|
-
|
|
182
|
-
Respond in json format with a hash of strings as keys and string arrays as values, at most three in length
|
|
183
|
-
|
|
184
|
-
user:
|
|
185
|
-
|
|
186
|
-
What other movies have the protagonists of the original gost busters played on, just the top.
|
|
187
|
-
EOF
|
|
188
|
-
sss 0
|
|
189
|
-
ppp LLM::OpenAI.ask prompt, format: :json
|
|
190
|
-
end
|
|
191
|
-
end
|
|
192
|
-
|
|
@@ -1,238 +0,0 @@
|
|
|
1
|
-
require File.expand_path(__FILE__).sub(%r(/test/.*), '/test/test_helper.rb')
|
|
2
|
-
require File.expand_path(__FILE__).sub(%r(.*/test/), '').sub(/test_(.*)\.rb/,'\1')
|
|
3
|
-
|
|
4
|
-
class TestLLMResponses < Test::Unit::TestCase
|
|
5
|
-
def test_ask
|
|
6
|
-
prompt =<<-EOF
|
|
7
|
-
system: you are a coding helper that only write code and comments without formatting so that it can work directly, avoid the initial and end commas ```.
|
|
8
|
-
user: write a script that sorts files in a directory
|
|
9
|
-
EOF
|
|
10
|
-
ppp LLM::Responses.ask prompt, model: 'gpt-4.1-nano'
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def _test_embeddings
|
|
14
|
-
Log.severity = 0
|
|
15
|
-
text =<<-EOF
|
|
16
|
-
Some text
|
|
17
|
-
EOF
|
|
18
|
-
emb = LLM::Responses.embed text, log_errors: true
|
|
19
|
-
assert(Float === emb.first)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def _test_tool_call_output_weather
|
|
23
|
-
Log.severity = 0
|
|
24
|
-
prompt =<<-EOF
|
|
25
|
-
function_call:
|
|
26
|
-
|
|
27
|
-
{"name":"get_current_temperature", "arguments":{"location":"London","unit":"Celsius"},"id":"tNTnsQq2s6jGh0npOh43AwDD"}
|
|
28
|
-
|
|
29
|
-
function_call_output:
|
|
30
|
-
|
|
31
|
-
{"id":"tNTnsQq2s6jGh0npOh43AwDD", "content":"It's 15 degrees and raining."}
|
|
32
|
-
|
|
33
|
-
user:
|
|
34
|
-
|
|
35
|
-
should i take an umbrella?
|
|
36
|
-
EOF
|
|
37
|
-
ppp LLM::Responses.ask prompt, model: 'gpt-4.1-nano'
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def _test_tool
|
|
41
|
-
prompt =<<-EOF
|
|
42
|
-
user:
|
|
43
|
-
What is the weather in London. Should I take my umbrella?
|
|
44
|
-
EOF
|
|
45
|
-
|
|
46
|
-
tools = [
|
|
47
|
-
{
|
|
48
|
-
"type": "function",
|
|
49
|
-
"name": "get_current_temperature",
|
|
50
|
-
"description": "Get the current temperature and raining conditions for a specific location",
|
|
51
|
-
"parameters": {
|
|
52
|
-
"type": "object",
|
|
53
|
-
"properties": {
|
|
54
|
-
"location": {
|
|
55
|
-
"type": "string",
|
|
56
|
-
"description": "The city and state, e.g., San Francisco, CA"
|
|
57
|
-
},
|
|
58
|
-
"unit": {
|
|
59
|
-
"type": "string",
|
|
60
|
-
"enum": ["Celsius", "Fahrenheit"],
|
|
61
|
-
"description": "The temperature unit to use. Infer this from the user's location."
|
|
62
|
-
}
|
|
63
|
-
},
|
|
64
|
-
"required": ["location", "unit"]
|
|
65
|
-
}
|
|
66
|
-
},
|
|
67
|
-
]
|
|
68
|
-
|
|
69
|
-
sss 1
|
|
70
|
-
respose = LLM::Responses.ask prompt, tool_choice: 'required', tools: tools, model: "gpt-4.1-nano", log_errors: true do |name,arguments|
|
|
71
|
-
"It's 15 degrees and raining."
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
ppp respose
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def _test_news
|
|
78
|
-
prompt =<<-EOF
|
|
79
|
-
websearch: true
|
|
80
|
-
|
|
81
|
-
user:
|
|
82
|
-
|
|
83
|
-
What was the top new in the US today?
|
|
84
|
-
EOF
|
|
85
|
-
ppp LLM::Responses.ask prompt
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def _test_image
|
|
89
|
-
prompt =<<-EOF
|
|
90
|
-
image: #{datafile_test 'cat.jpg'}
|
|
91
|
-
|
|
92
|
-
user:
|
|
93
|
-
|
|
94
|
-
What animal is represented in the image?
|
|
95
|
-
EOF
|
|
96
|
-
sss 0
|
|
97
|
-
ppp LLM::Responses.ask prompt
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def _test_json_output
|
|
101
|
-
prompt =<<-EOF
|
|
102
|
-
system:
|
|
103
|
-
|
|
104
|
-
Respond in json format with a hash of strings as keys and string arrays as values, at most three in length
|
|
105
|
-
|
|
106
|
-
user:
|
|
107
|
-
|
|
108
|
-
What other movies have the protagonists of the original gost busters played on, just the top.
|
|
109
|
-
EOF
|
|
110
|
-
sss 0
|
|
111
|
-
ppp LLM::Responses.ask prompt, format: :json
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
def _test_json_format
|
|
115
|
-
prompt =<<-EOF
|
|
116
|
-
user:
|
|
117
|
-
|
|
118
|
-
What other movies have the protagonists of the original gost busters played on.
|
|
119
|
-
Name each actor and the top movie they took part of
|
|
120
|
-
EOF
|
|
121
|
-
sss 0
|
|
122
|
-
|
|
123
|
-
format = {
|
|
124
|
-
name: 'actors_and_top_movies',
|
|
125
|
-
type: 'object',
|
|
126
|
-
properties: {},
|
|
127
|
-
additionalProperties: {type: :string}
|
|
128
|
-
}
|
|
129
|
-
ppp LLM::Responses.ask prompt, format: format
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
def _test_json_format_list
|
|
133
|
-
prompt =<<-EOF
|
|
134
|
-
user:
|
|
135
|
-
|
|
136
|
-
What other movies have the protagonists of the original gost busters played on.
|
|
137
|
-
Name each actor as keys and the top 3 movies they took part of as values
|
|
138
|
-
EOF
|
|
139
|
-
sss 0
|
|
140
|
-
|
|
141
|
-
format = {
|
|
142
|
-
name: 'actors_and_top_movies',
|
|
143
|
-
type: 'object',
|
|
144
|
-
properties: {},
|
|
145
|
-
additionalProperties: {type: :array, items: {type: :string}}
|
|
146
|
-
}
|
|
147
|
-
ppp LLM::Responses.ask prompt, format: format
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
def _test_json_format_actor_list
|
|
151
|
-
prompt =<<-EOF
|
|
152
|
-
user:
|
|
153
|
-
|
|
154
|
-
What other movies have the protagonists of the original gost busters played on.
|
|
155
|
-
Name each actor as keys and the top 3 movies they took part of as values
|
|
156
|
-
EOF
|
|
157
|
-
sss 0
|
|
158
|
-
|
|
159
|
-
format = {
|
|
160
|
-
name: 'actors_and_top_movies',
|
|
161
|
-
type: 'object',
|
|
162
|
-
properties: {},
|
|
163
|
-
additionalProperties: false,
|
|
164
|
-
items: {
|
|
165
|
-
type: 'object',
|
|
166
|
-
properties: {
|
|
167
|
-
name: {type: :string, description: 'actor name'},
|
|
168
|
-
movies: {type: :array, description: 'list of top 3 movies', items: {type: :string, description: 'movie title plus year in parenthesis'} },
|
|
169
|
-
additionalProperties: false
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
schema = {
|
|
175
|
-
"type": "object",
|
|
176
|
-
"properties": {
|
|
177
|
-
"people": {
|
|
178
|
-
"type": "array",
|
|
179
|
-
"items": {
|
|
180
|
-
"type": "object",
|
|
181
|
-
"properties": {
|
|
182
|
-
"name": { "type": "string" },
|
|
183
|
-
"movies": {
|
|
184
|
-
"type": "array",
|
|
185
|
-
"items": { "type": "string" },
|
|
186
|
-
"minItems": 3,
|
|
187
|
-
"maxItems": 3
|
|
188
|
-
}
|
|
189
|
-
},
|
|
190
|
-
"required": ["name", "movies"],
|
|
191
|
-
additionalProperties: false
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
},
|
|
195
|
-
additionalProperties: false,
|
|
196
|
-
"required": ["people"]
|
|
197
|
-
}
|
|
198
|
-
ppp LLM::Responses.ask prompt, format: schema
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
def _test_tool_gpt5
|
|
202
|
-
prompt =<<-EOF
|
|
203
|
-
user:
|
|
204
|
-
What is the weather in London. Should I take my umbrella?
|
|
205
|
-
EOF
|
|
206
|
-
|
|
207
|
-
tools = [
|
|
208
|
-
{
|
|
209
|
-
"type": "function",
|
|
210
|
-
"name": "get_current_temperature",
|
|
211
|
-
"description": "Get the current temperature and raining conditions for a specific location",
|
|
212
|
-
"parameters": {
|
|
213
|
-
"type": "object",
|
|
214
|
-
"properties": {
|
|
215
|
-
"location": {
|
|
216
|
-
"type": "string",
|
|
217
|
-
"description": "The city and state, e.g., San Francisco, CA"
|
|
218
|
-
},
|
|
219
|
-
"unit": {
|
|
220
|
-
"type": "string",
|
|
221
|
-
"enum": ["Celsius", "Fahrenheit"],
|
|
222
|
-
"description": "The temperature unit to use. Infer this from the user's location."
|
|
223
|
-
}
|
|
224
|
-
},
|
|
225
|
-
"required": ["location", "unit"]
|
|
226
|
-
}
|
|
227
|
-
},
|
|
228
|
-
]
|
|
229
|
-
|
|
230
|
-
sss 0
|
|
231
|
-
respose = LLM::Responses.ask prompt, tool_choice: 'required', tools: tools, model: "gpt-5", log_errors: true do |name,arguments|
|
|
232
|
-
"It's 15 degrees and raining."
|
|
233
|
-
end
|
|
234
|
-
|
|
235
|
-
ppp respose
|
|
236
|
-
end
|
|
237
|
-
end
|
|
238
|
-
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
require File.expand_path(__FILE__).sub(%r(/test/.*), '/test/test_helper.rb')
|
|
2
|
-
require File.expand_path(__FILE__).sub(%r(.*/test/), '').sub(/test_(.*)\.rb/,'\1')
|
|
3
|
-
|
|
4
|
-
class TestLLMParse < Test::Unit::TestCase
|
|
5
|
-
def test_parse
|
|
6
|
-
text=<<-EOF
|
|
7
|
-
hi
|
|
8
|
-
system: you are an asistant
|
|
9
|
-
user: Given the contents of this file:[[
|
|
10
|
-
line 1: 1
|
|
11
|
-
line 2: 2
|
|
12
|
-
line 3: 3
|
|
13
|
-
]]
|
|
14
|
-
Show me the lines in reverse order
|
|
15
|
-
EOF
|
|
16
|
-
|
|
17
|
-
assert_include LLM.parse(text).first[:content], 'hi'
|
|
18
|
-
assert_include LLM.parse(text).last[:content], 'reverse'
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def test_code
|
|
22
|
-
text=<<-EOF
|
|
23
|
-
hi
|
|
24
|
-
system: you are an asistant
|
|
25
|
-
user: Given the contents of this file:
|
|
26
|
-
```yaml
|
|
27
|
-
key: value
|
|
28
|
-
key2: value2
|
|
29
|
-
```
|
|
30
|
-
Show me the lines in reverse order
|
|
31
|
-
EOF
|
|
32
|
-
|
|
33
|
-
assert_include LLM.parse(text).last[:content], 'key2'
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def test_lines
|
|
37
|
-
text=<<-EOF
|
|
38
|
-
system: you are an asistant
|
|
39
|
-
user: I have a question
|
|
40
|
-
EOF
|
|
41
|
-
|
|
42
|
-
assert_include LLM.parse(text).last[:content], 'question'
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def test_blocks
|
|
46
|
-
text=<<-EOF
|
|
47
|
-
system:
|
|
48
|
-
|
|
49
|
-
you are an asistant
|
|
50
|
-
|
|
51
|
-
user:
|
|
52
|
-
|
|
53
|
-
I have a question
|
|
54
|
-
|
|
55
|
-
EOF
|
|
56
|
-
|
|
57
|
-
assert_include LLM.parse(text).last[:content], 'question'
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def test_no_role
|
|
61
|
-
text=<<-EOF
|
|
62
|
-
I have a question
|
|
63
|
-
EOF
|
|
64
|
-
|
|
65
|
-
assert_include LLM.parse(text).last[:content], 'question'
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
def test_cmd
|
|
70
|
-
text=<<-EOF
|
|
71
|
-
How many files are there:
|
|
72
|
-
|
|
73
|
-
[[cmd list of files
|
|
74
|
-
echo "file1 file2"
|
|
75
|
-
]]
|
|
76
|
-
EOF
|
|
77
|
-
|
|
78
|
-
assert_equal :user, LLM.parse(text).last[:role]
|
|
79
|
-
assert_include LLM.parse(text).first[:content], 'file1'
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def test_directory
|
|
83
|
-
TmpFile.with_path do |tmpdir|
|
|
84
|
-
tmpdir.file1.write "foo"
|
|
85
|
-
tmpdir.file2.write "bar"
|
|
86
|
-
text=<<-EOF
|
|
87
|
-
How many files are there:
|
|
88
|
-
|
|
89
|
-
[[directory DIR
|
|
90
|
-
#{tmpdir}
|
|
91
|
-
]]
|
|
92
|
-
EOF
|
|
93
|
-
|
|
94
|
-
assert_include LLM.parse(text).first[:content], 'file1'
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
|