soka 0.0.4 → 0.0.6
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/.rubocop.yml +1 -1
- data/CHANGELOG.md +46 -0
- data/CLAUDE.md +19 -4
- data/README.md +28 -22
- data/examples/1_basic.rb +0 -2
- data/examples/2_event_handling.rb +0 -1
- data/examples/3_memory.rb +0 -2
- data/lib/soka/agent.rb +3 -3
- data/lib/soka/agent_tool.rb +10 -16
- data/lib/soka/agents/dsl_methods.rb +1 -7
- data/lib/soka/agents/hook_manager.rb +4 -6
- data/lib/soka/configuration.rb +2 -3
- data/lib/soka/engines/concerns/response_parser.rb +9 -21
- data/lib/soka/engines/concerns/response_processor.rb +12 -1
- data/lib/soka/engines/prompts/base.rb +103 -0
- data/lib/soka/engines/prompts/format_helpers.rb +43 -0
- data/lib/soka/engines/prompts/instructions.rb +86 -0
- data/lib/soka/engines/prompts/workflow_rules.rb +98 -0
- data/lib/soka/engines/prompts.rb +13 -0
- data/lib/soka/engines/react.rb +6 -7
- data/lib/soka/engines/reasoning_context.rb +0 -12
- data/lib/soka/llm.rb +4 -4
- data/lib/soka/llms/anthropic.rb +17 -21
- data/lib/soka/llms/base.rb +1 -2
- data/lib/soka/llms/gemini.rb +2 -3
- data/lib/soka/llms/openai.rb +42 -36
- data/lib/soka/result.rb +1 -8
- data/lib/soka/version.rb +1 -1
- data/lib/soka.rb +1 -0
- metadata +26 -5
- data/lib/soka/engines/concerns/prompt_template.rb +0 -121
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Soka
|
4
|
+
module Engines
|
5
|
+
module Prompts
|
6
|
+
# Helper methods for formatting prompt components
|
7
|
+
module FormatHelpers
|
8
|
+
private
|
9
|
+
|
10
|
+
# Format tools description for prompt
|
11
|
+
# @param tools [Array] The tools available
|
12
|
+
# @return [String] Formatted tools description
|
13
|
+
def format_tools_description(tools)
|
14
|
+
return 'No tools available.' if tools.empty?
|
15
|
+
|
16
|
+
tools.map do |tool|
|
17
|
+
schema = tool.class.to_h
|
18
|
+
params_desc = format_parameters(schema[:parameters])
|
19
|
+
|
20
|
+
"- #{schema[:name]}: #{schema[:description]}\n Parameters: \n#{params_desc}"
|
21
|
+
end.join("\n")
|
22
|
+
end
|
23
|
+
|
24
|
+
# Format parameters for tool description
|
25
|
+
# @param params_schema [Hash] The parameters schema
|
26
|
+
# @return [String] Formatted parameters description
|
27
|
+
def format_parameters(params_schema)
|
28
|
+
return 'none' if params_schema[:properties].empty?
|
29
|
+
|
30
|
+
properties = params_schema[:properties].map do |name, config|
|
31
|
+
required = params_schema[:required].include?(name.to_s) ? '(required)' : '(optional)'
|
32
|
+
type = config[:type]
|
33
|
+
desc = config[:description]
|
34
|
+
|
35
|
+
" - #{name} #{required} [#{type}] - #{desc}"
|
36
|
+
end
|
37
|
+
|
38
|
+
properties.join("\n")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Soka
|
4
|
+
module Engines
|
5
|
+
module Prompts
|
6
|
+
# Module for building instruction components
|
7
|
+
module Instructions
|
8
|
+
private
|
9
|
+
|
10
|
+
# Build iteration limit warning
|
11
|
+
# @return [String] The iteration limit warning
|
12
|
+
def build_iteration_limit_warning
|
13
|
+
return '' unless respond_to?(:max_iterations) && max_iterations
|
14
|
+
|
15
|
+
<<~WARNING
|
16
|
+
⏰ ITERATION LIMIT: You have a maximum of #{max_iterations} iterations to complete this task.
|
17
|
+
- Each Thought/Action cycle counts as one iteration
|
18
|
+
- Plan your approach efficiently to stay within this limit
|
19
|
+
- If you cannot complete the task within #{max_iterations} iterations, provide your best answer with what you have
|
20
|
+
WARNING
|
21
|
+
end
|
22
|
+
|
23
|
+
# Build thinking instruction based on language
|
24
|
+
# @param language [String, nil] The language to use for thinking
|
25
|
+
# @return [String] The thinking instruction
|
26
|
+
def build_thinking_instruction(language)
|
27
|
+
return '' unless language
|
28
|
+
|
29
|
+
<<~INSTRUCTION
|
30
|
+
🌐 THINKING LANGUAGE:
|
31
|
+
Use #{language} for your reasoning WITHIN the <Thought> XML tags.
|
32
|
+
This affects the content inside tags, not the tag structure itself.
|
33
|
+
INSTRUCTION
|
34
|
+
end
|
35
|
+
|
36
|
+
# Step format example
|
37
|
+
# @return [String] The step format example
|
38
|
+
def step_format_example
|
39
|
+
<<~FORMAT
|
40
|
+
📝 XML TAG FORMAT FOR EACH STEP:
|
41
|
+
|
42
|
+
1️⃣ THINKING PHASE (Required):
|
43
|
+
<Thought>
|
44
|
+
MAXIMUM 30 WORDS - Be extremely concise!
|
45
|
+
Use first-person perspective (I, me, my).
|
46
|
+
NEVER mention: "LLM", "AI", "formatting for", "organizing for someone".
|
47
|
+
NEVER say: "I will act as", "I will play the role of", "as an expert".
|
48
|
+
BE DIRECT: "I'll check", "Let me see", "Looking at this".
|
49
|
+
Keep it light and witty within the word limit.
|
50
|
+
</Thought>
|
51
|
+
|
52
|
+
2️⃣ ACTION PHASE (When needed):
|
53
|
+
<Action>
|
54
|
+
{"tool": "tool_name", "parameters": {"param1": "value1", "param2": "value2"}}
|
55
|
+
</Action>
|
56
|
+
|
57
|
+
⚠️ CRITICAL: Each tag MUST have both opening <TagName> and closing </TagName>.
|
58
|
+
The content between tags follows any custom instructions provided.
|
59
|
+
FORMAT
|
60
|
+
end
|
61
|
+
|
62
|
+
# Critical format for final answer
|
63
|
+
# @return [String] The critical format instructions
|
64
|
+
def final_answer_critical_format
|
65
|
+
<<~CRITICAL
|
66
|
+
⚠️ CRITICAL - FINAL ANSWER XML TAG FORMAT:
|
67
|
+
When you have the complete answer, YOU MUST use XML-style tags:
|
68
|
+
|
69
|
+
<FinalAnswer>
|
70
|
+
State the result directly without explanation.
|
71
|
+
No justification or reasoning needed - just the answer.
|
72
|
+
Maximum 300 words. Be direct and concise.
|
73
|
+
</FinalAnswer>
|
74
|
+
|
75
|
+
🚨 PARSER REQUIREMENTS:
|
76
|
+
- The system parser REQUIRES both opening <FinalAnswer> and closing </FinalAnswer> tags
|
77
|
+
- Without proper XML tags, the system CANNOT detect task completion
|
78
|
+
- The tags are case-sensitive and must match exactly
|
79
|
+
- Final answer MUST NOT exceed 300 words
|
80
|
+
- NO over-explanation - direct results only
|
81
|
+
CRITICAL
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Soka
|
4
|
+
module Engines
|
5
|
+
module Prompts
|
6
|
+
# Module for ReAct workflow rules
|
7
|
+
module WorkflowRules
|
8
|
+
private
|
9
|
+
|
10
|
+
# Action format rules
|
11
|
+
# @return [String] The action format rules
|
12
|
+
def action_format_rules
|
13
|
+
<<~RULES
|
14
|
+
🔄 REACT WORKFLOW WITH XML TAGS:
|
15
|
+
|
16
|
+
STOP HERE after each Action. Do NOT include <Observation> in your response.
|
17
|
+
The system will execute the tool and provide the observation wrapped in <Observation> tags.
|
18
|
+
|
19
|
+
After receiving the observation, you can continue with more Thought/Action cycles or provide a final answer.
|
20
|
+
|
21
|
+
#{react_flow_example}
|
22
|
+
|
23
|
+
#{xml_tag_requirements}
|
24
|
+
RULES
|
25
|
+
end
|
26
|
+
|
27
|
+
# ReAct flow example
|
28
|
+
# @return [String] The ReAct flow example
|
29
|
+
def react_flow_example
|
30
|
+
<<~EXAMPLE
|
31
|
+
📝 EXAMPLE OF COMPLETE REACT FLOW WITH XML TAGS:
|
32
|
+
|
33
|
+
Step 1: Your response
|
34
|
+
<Thought>Math problem! I'll use the calculator tool for 2+2.</Thought>
|
35
|
+
<Action>{"tool": "calculator", "parameters": {"expression": "2+2"}}</Action>
|
36
|
+
|
37
|
+
Step 2: System provides
|
38
|
+
<Observation>4</Observation>
|
39
|
+
|
40
|
+
Step 3: Your response
|
41
|
+
<Thought>Got it - the answer is 4!</Thought>
|
42
|
+
<FinalAnswer>4</FinalAnswer>
|
43
|
+
EXAMPLE
|
44
|
+
end
|
45
|
+
|
46
|
+
# XML tag requirements
|
47
|
+
# @return [String] The XML tag requirements
|
48
|
+
def xml_tag_requirements
|
49
|
+
<<~REQUIREMENTS
|
50
|
+
🚨 XML TAG REQUIREMENTS AND RULES:
|
51
|
+
|
52
|
+
1. 🏷️ MANDATORY XML STRUCTURE:
|
53
|
+
- Always wrap content in appropriate XML tags
|
54
|
+
- Tags: <Thought>, <Action>, <FinalAnswer>
|
55
|
+
- Each tag MUST have matching closing tag
|
56
|
+
|
57
|
+
2. 💭 THINKING PHASE:
|
58
|
+
- Always start with <Thought>...</Thought>
|
59
|
+
- MAXIMUM 30 WORDS per thought
|
60
|
+
- Use first-person perspective (I, me, my)
|
61
|
+
- AVOID: "LLM", "AI", "formatting for", "organizing for"
|
62
|
+
- AVOID: "act as", "play role of", "as an expert", "I will be"
|
63
|
+
- BE DIRECT: Use natural language like "I'll check", "Let me see"
|
64
|
+
- Be concise and witty
|
65
|
+
- Custom instructions affect HOW you think, not WHETHER you use tags
|
66
|
+
|
67
|
+
3. 🔧 ACTION FORMAT:
|
68
|
+
- <Action> content MUST be valid JSON on a single line
|
69
|
+
- Format: {"tool": "name", "parameters": {...}}
|
70
|
+
- Empty parameters: {"tool": "name", "parameters": {}}
|
71
|
+
|
72
|
+
4. 👁️ OBSERVATION:
|
73
|
+
- NEVER create <Observation> tags yourself
|
74
|
+
- System provides these automatically
|
75
|
+
|
76
|
+
5. ✅ FINAL ANSWER:
|
77
|
+
- MUST use <FinalAnswer>...</FinalAnswer> tags
|
78
|
+
- Both opening AND closing tags REQUIRED
|
79
|
+
- System cannot detect completion without these tags
|
80
|
+
- No text after closing </FinalAnswer> tag
|
81
|
+
- Maximum 300 words
|
82
|
+
- Direct results only - NO explanations or justifications
|
83
|
+
|
84
|
+
6. 🎯 EFFICIENCY:
|
85
|
+
- Limited iterations available
|
86
|
+
- Think harder upfront to minimize tool calls
|
87
|
+
- Prioritize essential actions
|
88
|
+
|
89
|
+
7. 📋 CUSTOM INSTRUCTIONS SCOPE:
|
90
|
+
- Custom instructions modify content WITHIN tags
|
91
|
+
- They DO NOT change the XML tag structure requirement
|
92
|
+
- ReAct workflow with XML tags is ALWAYS required
|
93
|
+
REQUIREMENTS
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
data/lib/soka/engines/react.rb
CHANGED
@@ -1,17 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'json'
|
4
|
-
|
5
3
|
module Soka
|
6
4
|
module Engines
|
7
5
|
# ReAct (Reasoning and Acting) engine implementation
|
8
6
|
class React < Base
|
7
|
+
include Prompts
|
9
8
|
include Concerns::ResponseProcessor
|
10
|
-
include Concerns::PromptTemplate
|
11
9
|
include Concerns::ResponseParser
|
12
10
|
include Concerns::ResultBuilder
|
13
11
|
|
14
|
-
ReasonResult = Struct.new(:input, :thoughts, :final_answer, :status, :error,
|
12
|
+
ReasonResult = Struct.new(:input, :thoughts, :final_answer, :status, :error,
|
15
13
|
keyword_init: true) do
|
16
14
|
def successful?
|
17
15
|
status == :success
|
@@ -35,12 +33,13 @@ module Soka
|
|
35
33
|
# @param context [ReasoningContext] The reasoning context
|
36
34
|
# @return [ReasonResult, nil] The result if found, nil otherwise
|
37
35
|
def iterate_reasoning(context)
|
38
|
-
max_iterations.times do
|
36
|
+
max_iterations.times do |index|
|
37
|
+
context.iteration = index # Set current iteration number
|
39
38
|
result = process_iteration(context)
|
40
39
|
return result if result
|
41
|
-
|
42
|
-
context.increment_iteration!
|
43
40
|
end
|
41
|
+
# When max iterations reached, ensure iteration count is correct
|
42
|
+
context.iteration = max_iterations
|
44
43
|
nil
|
45
44
|
end
|
46
45
|
|
@@ -37,18 +37,6 @@ module Soka
|
|
37
37
|
@event_handler.call(event)
|
38
38
|
end
|
39
39
|
|
40
|
-
# Check if we've reached the maximum number of iterations
|
41
|
-
# @return [Boolean] true if max iterations reached
|
42
|
-
def max_iterations_reached?
|
43
|
-
@iteration >= @max_iterations
|
44
|
-
end
|
45
|
-
|
46
|
-
# Increment the iteration counter
|
47
|
-
# @return [Integer] The new iteration count
|
48
|
-
def increment_iteration!
|
49
|
-
@iteration += 1
|
50
|
-
end
|
51
|
-
|
52
40
|
# Get the current iteration number (1-based for display)
|
53
41
|
# @return [Integer] The current iteration number for display
|
54
42
|
def current_step
|
data/lib/soka/llm.rb
CHANGED
@@ -69,14 +69,14 @@ module Soka
|
|
69
69
|
# @param provider_name [Symbol] Provider type
|
70
70
|
# @param options [Hash] Provider options
|
71
71
|
# @return [LLMs::Base] Provider instance
|
72
|
-
def create_provider(provider_name,
|
72
|
+
def create_provider(provider_name, ...)
|
73
73
|
case provider_name.to_sym
|
74
74
|
when :gemini
|
75
|
-
LLMs::Gemini.new(
|
75
|
+
LLMs::Gemini.new(...)
|
76
76
|
when :openai
|
77
|
-
LLMs::OpenAI.new(
|
77
|
+
LLMs::OpenAI.new(...)
|
78
78
|
when :anthropic
|
79
|
-
LLMs::Anthropic.new(
|
79
|
+
LLMs::Anthropic.new(...)
|
80
80
|
else
|
81
81
|
raise LLMError, "Unknown LLM provider: #{provider_name}"
|
82
82
|
end
|
data/lib/soka/llms/anthropic.rb
CHANGED
@@ -6,6 +6,21 @@ module Soka
|
|
6
6
|
class Anthropic < Base
|
7
7
|
ENV_KEY = 'ANTHROPIC_API_KEY'
|
8
8
|
|
9
|
+
def chat(messages, **params)
|
10
|
+
request_params = build_request_params(messages, params)
|
11
|
+
|
12
|
+
response = connection.post do |req|
|
13
|
+
req.url '/v1/messages'
|
14
|
+
req.headers['x-api-key'] = api_key
|
15
|
+
req.headers['anthropic-version'] = options[:anthropic_version]
|
16
|
+
req.body = request_params
|
17
|
+
end
|
18
|
+
|
19
|
+
parse_response(response)
|
20
|
+
rescue Faraday::Error => e
|
21
|
+
handle_error(e)
|
22
|
+
end
|
23
|
+
|
9
24
|
private
|
10
25
|
|
11
26
|
def default_model
|
@@ -21,30 +36,11 @@ module Soka
|
|
21
36
|
temperature: 0.7,
|
22
37
|
top_p: 1.0,
|
23
38
|
top_k: 1,
|
24
|
-
|
25
|
-
|
39
|
+
anthropic_version: '2023-06-01',
|
40
|
+
max_tokens: 2048
|
26
41
|
}
|
27
42
|
end
|
28
43
|
|
29
|
-
public
|
30
|
-
|
31
|
-
def chat(messages, **params)
|
32
|
-
request_params = build_request_params(messages, params)
|
33
|
-
|
34
|
-
response = connection.post do |req|
|
35
|
-
req.url '/v1/messages'
|
36
|
-
req.headers['x-api-key'] = api_key
|
37
|
-
req.headers['anthropic-version'] = options[:anthropic_version]
|
38
|
-
req.body = request_params
|
39
|
-
end
|
40
|
-
|
41
|
-
parse_response(response)
|
42
|
-
rescue Faraday::Error => e
|
43
|
-
handle_error(e)
|
44
|
-
end
|
45
|
-
|
46
|
-
private
|
47
|
-
|
48
44
|
def build_request_params(messages, params)
|
49
45
|
formatted_messages, system_prompt = extract_system_prompt(messages)
|
50
46
|
request = build_base_request(formatted_messages, params)
|
data/lib/soka/llms/base.rb
CHANGED
@@ -57,8 +57,7 @@ module Soka
|
|
57
57
|
faraday.request :json
|
58
58
|
faraday.response :json
|
59
59
|
faraday.adapter Faraday.default_adapter
|
60
|
-
faraday.options.timeout =
|
61
|
-
faraday.options.open_timeout = options[:open_timeout] || 10
|
60
|
+
faraday.options.timeout = 60
|
62
61
|
end
|
63
62
|
end
|
64
63
|
|
data/lib/soka/llms/gemini.rb
CHANGED
@@ -20,8 +20,7 @@ module Soka
|
|
20
20
|
{
|
21
21
|
temperature: 0.7,
|
22
22
|
top_p: 1.0,
|
23
|
-
top_k: 1
|
24
|
-
max_output_tokens: 2048
|
23
|
+
top_k: 1
|
25
24
|
}
|
26
25
|
end
|
27
26
|
|
@@ -50,7 +49,7 @@ module Soka
|
|
50
49
|
temperature: params[:temperature] || options[:temperature],
|
51
50
|
topP: params[:top_p] || options[:top_p],
|
52
51
|
topK: params[:top_k] || options[:top_k],
|
53
|
-
|
52
|
+
thinkingConfig: { thinkingBudget: 512 }
|
54
53
|
}
|
55
54
|
}
|
56
55
|
end
|
data/lib/soka/llms/openai.rb
CHANGED
@@ -6,33 +6,11 @@ module Soka
|
|
6
6
|
class OpenAI < Base
|
7
7
|
ENV_KEY = 'OPENAI_API_KEY'
|
8
8
|
|
9
|
-
private
|
10
|
-
|
11
|
-
def default_model
|
12
|
-
'gpt-4.1-mini'
|
13
|
-
end
|
14
|
-
|
15
|
-
def base_url
|
16
|
-
'https://api.openai.com'
|
17
|
-
end
|
18
|
-
|
19
|
-
def default_options
|
20
|
-
{
|
21
|
-
temperature: 0.7,
|
22
|
-
top_p: 1.0,
|
23
|
-
frequency_penalty: 0,
|
24
|
-
presence_penalty: 0,
|
25
|
-
max_tokens: 2048
|
26
|
-
}
|
27
|
-
end
|
28
|
-
|
29
|
-
public
|
30
|
-
|
31
9
|
def chat(messages, **params)
|
32
10
|
request_params = build_request_params(messages, params)
|
33
11
|
|
34
12
|
response = connection.post do |req|
|
35
|
-
req.url '/v1/
|
13
|
+
req.url '/v1/responses'
|
36
14
|
req.headers['Authorization'] = "Bearer #{api_key}"
|
37
15
|
req.body = request_params
|
38
16
|
end
|
@@ -44,16 +22,35 @@ module Soka
|
|
44
22
|
|
45
23
|
private
|
46
24
|
|
25
|
+
def default_model
|
26
|
+
'gpt-5-mini'
|
27
|
+
end
|
28
|
+
|
29
|
+
def base_url
|
30
|
+
'https://api.openai.com'
|
31
|
+
end
|
32
|
+
|
47
33
|
def build_request_params(messages, params)
|
48
|
-
{
|
34
|
+
request_params = {
|
49
35
|
model: model,
|
50
|
-
|
51
|
-
temperature: params[:temperature] || options[:temperature],
|
52
|
-
top_p: params[:top_p] || options[:top_p],
|
53
|
-
frequency_penalty: params[:frequency_penalty] || options[:frequency_penalty],
|
54
|
-
presence_penalty: params[:presence_penalty] || options[:presence_penalty],
|
55
|
-
max_tokens: params[:max_tokens] || options[:max_tokens]
|
36
|
+
input: messages
|
56
37
|
}
|
38
|
+
|
39
|
+
# Add max_output_tokens if provided (Responses API uses max_output_tokens)
|
40
|
+
request_params[:max_output_tokens] = params[:max_tokens] if params[:max_tokens]
|
41
|
+
add_reasoning_effort(request_params)
|
42
|
+
|
43
|
+
request_params
|
44
|
+
end
|
45
|
+
|
46
|
+
def add_reasoning_effort(request_params)
|
47
|
+
return unless allowed_reasoning_prefix_models?
|
48
|
+
|
49
|
+
request_params[:reasoning] = { effort: 'minimal', summary: 'auto' }
|
50
|
+
end
|
51
|
+
|
52
|
+
def allowed_reasoning_prefix_models?
|
53
|
+
model.start_with?('gpt-5') && !model.start_with?('gpt-5-chat-latest')
|
57
54
|
end
|
58
55
|
|
59
56
|
def parse_response(response)
|
@@ -70,18 +67,27 @@ module Soka
|
|
70
67
|
end
|
71
68
|
|
72
69
|
def build_result_from_response(body)
|
73
|
-
|
74
|
-
|
70
|
+
# Extract text from the Responses API format
|
71
|
+
output_text = extract_output_text(body['output'])
|
72
|
+
|
73
|
+
# Get the status to determine finish reason
|
74
|
+
finish_reason = body['status'] == 'completed' ? 'stop' : body['status']
|
75
75
|
|
76
76
|
Result.new(
|
77
77
|
model: body['model'],
|
78
|
-
content:
|
79
|
-
input_tokens: body.dig('usage', '
|
80
|
-
output_tokens: body.dig('usage', '
|
81
|
-
finish_reason:
|
78
|
+
content: output_text,
|
79
|
+
input_tokens: body.dig('usage', 'input_tokens'),
|
80
|
+
output_tokens: body.dig('usage', 'output_tokens'),
|
81
|
+
finish_reason: finish_reason,
|
82
82
|
raw_response: body
|
83
83
|
)
|
84
84
|
end
|
85
|
+
|
86
|
+
def extract_output_text(output_items)
|
87
|
+
message = output_items.find { |item| item['type'] == 'message' }
|
88
|
+
content = message['content'].find { |content| content['type'] == 'output_text' }
|
89
|
+
content['text']
|
90
|
+
end
|
85
91
|
end
|
86
92
|
end
|
87
93
|
end
|
data/lib/soka/result.rb
CHANGED
@@ -37,12 +37,6 @@ module Soka
|
|
37
37
|
status == :failed
|
38
38
|
end
|
39
39
|
|
40
|
-
# Check if the result timed out
|
41
|
-
# @return [Boolean]
|
42
|
-
def timeout?
|
43
|
-
status == :timeout
|
44
|
-
end
|
45
|
-
|
46
40
|
# Check if max iterations were reached
|
47
41
|
# @return [Boolean]
|
48
42
|
def max_iterations_reached?
|
@@ -66,7 +60,7 @@ module Soka
|
|
66
60
|
# Convert to JSON string
|
67
61
|
# @return [String]
|
68
62
|
def to_json(*)
|
69
|
-
|
63
|
+
Oj.dump(to_h, mode: :compat)
|
70
64
|
end
|
71
65
|
|
72
66
|
# Get a summary of the result
|
@@ -117,7 +111,6 @@ module Soka
|
|
117
111
|
{
|
118
112
|
success: "Success: #{truncate(final_answer)}",
|
119
113
|
failed: "Failed: #{error}",
|
120
|
-
timeout: 'Timeout: Execution exceeded time limit',
|
121
114
|
max_iterations_reached: "Max iterations reached: #{iterations} iterations"
|
122
115
|
}
|
123
116
|
end
|
data/lib/soka/version.rb
CHANGED
data/lib/soka.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: soka
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- jiunjiun
|
8
|
+
autorequire:
|
8
9
|
bindir: bin
|
9
10
|
cert_chain: []
|
10
|
-
date:
|
11
|
+
date: 2025-08-12 00:00:00.000000000 Z
|
11
12
|
dependencies:
|
12
13
|
- !ruby/object:Gem::Dependency
|
13
14
|
name: faraday
|
@@ -23,6 +24,20 @@ dependencies:
|
|
23
24
|
- - "~>"
|
24
25
|
- !ruby/object:Gem::Version
|
25
26
|
version: '2.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: oj
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.16'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.16'
|
26
41
|
- !ruby/object:Gem::Dependency
|
27
42
|
name: zeitwerk
|
28
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -75,10 +90,14 @@ files:
|
|
75
90
|
- lib/soka/agents/tool_builder.rb
|
76
91
|
- lib/soka/configuration.rb
|
77
92
|
- lib/soka/engines/base.rb
|
78
|
-
- lib/soka/engines/concerns/prompt_template.rb
|
79
93
|
- lib/soka/engines/concerns/response_parser.rb
|
80
94
|
- lib/soka/engines/concerns/response_processor.rb
|
81
95
|
- lib/soka/engines/concerns/result_builder.rb
|
96
|
+
- lib/soka/engines/prompts.rb
|
97
|
+
- lib/soka/engines/prompts/base.rb
|
98
|
+
- lib/soka/engines/prompts/format_helpers.rb
|
99
|
+
- lib/soka/engines/prompts/instructions.rb
|
100
|
+
- lib/soka/engines/prompts/workflow_rules.rb
|
82
101
|
- lib/soka/engines/react.rb
|
83
102
|
- lib/soka/engines/reasoning_context.rb
|
84
103
|
- lib/soka/llm.rb
|
@@ -98,6 +117,7 @@ metadata:
|
|
98
117
|
source_code_uri: https://github.com/jiunjiun/soka
|
99
118
|
changelog_uri: https://github.com/jiunjiun/soka/blob/main/CHANGELOG.md
|
100
119
|
rubygems_mfa_required: 'true'
|
120
|
+
post_install_message:
|
101
121
|
rdoc_options: []
|
102
122
|
require_paths:
|
103
123
|
- lib
|
@@ -105,14 +125,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
105
125
|
requirements:
|
106
126
|
- - ">="
|
107
127
|
- !ruby/object:Gem::Version
|
108
|
-
version: '3.
|
128
|
+
version: '3.1'
|
109
129
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
130
|
requirements:
|
111
131
|
- - ">="
|
112
132
|
- !ruby/object:Gem::Version
|
113
133
|
version: '0'
|
114
134
|
requirements: []
|
115
|
-
rubygems_version: 3.
|
135
|
+
rubygems_version: 3.3.27
|
136
|
+
signing_key:
|
116
137
|
specification_version: 4
|
117
138
|
summary: A Ruby ReAct Agent Framework with multi-LLM support
|
118
139
|
test_files: []
|