google-adk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +58 -0
- data/LICENSE.txt +21 -0
- data/README.md +193 -0
- data/google-adk.gemspec +51 -0
- data/lib/google/adk/agents/base_agent.rb +149 -0
- data/lib/google/adk/agents/llm_agent.rb +322 -0
- data/lib/google/adk/agents/simple_llm_agent.rb +67 -0
- data/lib/google/adk/agents/workflow_agents/loop_agent.rb +116 -0
- data/lib/google/adk/agents/workflow_agents/parallel_agent.rb +138 -0
- data/lib/google/adk/agents/workflow_agents/sequential_agent.rb +108 -0
- data/lib/google/adk/clients/gemini_client.rb +90 -0
- data/lib/google/adk/context.rb +241 -0
- data/lib/google/adk/events.rb +191 -0
- data/lib/google/adk/runner.rb +210 -0
- data/lib/google/adk/session.rb +261 -0
- data/lib/google/adk/tools/agent_tool.rb +60 -0
- data/lib/google/adk/tools/base_tool.rb +34 -0
- data/lib/google/adk/tools/function_tool.rb +140 -0
- data/lib/google/adk/version.rb +7 -0
- data/lib/google/adk.rb +30 -0
- data/lib/google-adk.rb +3 -0
- metadata +253 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Google
|
|
4
|
+
module ADK
|
|
5
|
+
# Agent that executes sub-agents sequentially
|
|
6
|
+
class SequentialAgent < BaseAgent
|
|
7
|
+
attr_reader :agents
|
|
8
|
+
|
|
9
|
+
# Initialize a sequential agent
|
|
10
|
+
#
|
|
11
|
+
# @param name [String] Agent name
|
|
12
|
+
# @param description [String] Agent description (optional)
|
|
13
|
+
# @param agents [Array<BaseAgent>] Agents to execute in order
|
|
14
|
+
# @param before_agent_callback [Proc] Callback before agent execution
|
|
15
|
+
# @param after_agent_callback [Proc] Callback after agent execution
|
|
16
|
+
# @raise [ArgumentError] If no agents provided
|
|
17
|
+
def initialize(name:, agents:, description: nil,
|
|
18
|
+
before_agent_callback: nil, after_agent_callback: nil)
|
|
19
|
+
raise ArgumentError, "Sequential agent requires at least one agent" if agents.empty?
|
|
20
|
+
|
|
21
|
+
super(
|
|
22
|
+
name: name,
|
|
23
|
+
description: description || "Executes #{agents.length} agents sequentially",
|
|
24
|
+
sub_agents: agents,
|
|
25
|
+
before_agent_callback: before_agent_callback,
|
|
26
|
+
after_agent_callback: after_agent_callback
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
@agents = agents
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Run agents sequentially
|
|
33
|
+
#
|
|
34
|
+
# @param message [String] Initial message
|
|
35
|
+
# @param context [InvocationContext] Invocation context
|
|
36
|
+
# @yield [Event] Events during execution
|
|
37
|
+
def run_async(message, context: nil)
|
|
38
|
+
Enumerator.new do |yielder|
|
|
39
|
+
invocation_id = context&.invocation_id || "seq-#{SecureRandom.uuid}"
|
|
40
|
+
|
|
41
|
+
# Yield start event
|
|
42
|
+
start_event = Event.new(
|
|
43
|
+
invocation_id: invocation_id,
|
|
44
|
+
author: @name,
|
|
45
|
+
content: "Starting sequential execution with #{@agents.length} agents"
|
|
46
|
+
)
|
|
47
|
+
yielder << start_event
|
|
48
|
+
|
|
49
|
+
# Execute each agent in sequence
|
|
50
|
+
current_input = message
|
|
51
|
+
@agents.each_with_index do |agent, index|
|
|
52
|
+
begin
|
|
53
|
+
# Yield progress event
|
|
54
|
+
progress_event = Event.new(
|
|
55
|
+
invocation_id: invocation_id,
|
|
56
|
+
author: @name,
|
|
57
|
+
content: "Executing agent #{index + 1}/#{@agents.length}: #{agent.name}"
|
|
58
|
+
)
|
|
59
|
+
yielder << progress_event
|
|
60
|
+
|
|
61
|
+
# Run the agent
|
|
62
|
+
agent_output = nil
|
|
63
|
+
if agent.respond_to?(:run_async)
|
|
64
|
+
agent.run_async(current_input, context: context).each do |event|
|
|
65
|
+
yielder << event
|
|
66
|
+
# Capture last content as output for next agent
|
|
67
|
+
agent_output = event.content if event.content
|
|
68
|
+
end
|
|
69
|
+
else
|
|
70
|
+
# For agents that don't implement run_async
|
|
71
|
+
error_event = Event.new(
|
|
72
|
+
invocation_id: invocation_id,
|
|
73
|
+
author: @name,
|
|
74
|
+
content: "Agent #{agent.name} does not implement run_async"
|
|
75
|
+
)
|
|
76
|
+
yielder << error_event
|
|
77
|
+
agent_output = current_input
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Use this agent's output as next agent's input
|
|
81
|
+
current_input = agent_output || current_input
|
|
82
|
+
|
|
83
|
+
rescue StandardError => e
|
|
84
|
+
# Handle errors gracefully
|
|
85
|
+
error_event = Event.new(
|
|
86
|
+
invocation_id: invocation_id,
|
|
87
|
+
author: @name,
|
|
88
|
+
content: "Error in agent #{agent.name}: #{e.message}"
|
|
89
|
+
)
|
|
90
|
+
yielder << error_event
|
|
91
|
+
|
|
92
|
+
# Continue with original input if agent failed
|
|
93
|
+
current_input = message
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Yield completion event
|
|
98
|
+
end_event = Event.new(
|
|
99
|
+
invocation_id: invocation_id,
|
|
100
|
+
author: @name,
|
|
101
|
+
content: "Completed sequential execution. Final output: #{current_input}"
|
|
102
|
+
)
|
|
103
|
+
yielder << end_event
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "faraday"
|
|
4
|
+
require "json"
|
|
5
|
+
|
|
6
|
+
module Google
|
|
7
|
+
module ADK
|
|
8
|
+
# Client for interacting with Google's Gemini API
|
|
9
|
+
class GeminiClient
|
|
10
|
+
API_BASE_URL = "https://generativelanguage.googleapis.com"
|
|
11
|
+
|
|
12
|
+
attr_reader :api_key
|
|
13
|
+
|
|
14
|
+
def initialize(api_key: nil)
|
|
15
|
+
@api_key = api_key || ENV["GEMINI_API_KEY"]
|
|
16
|
+
raise ConfigurationError, "GEMINI_API_KEY not set" unless @api_key
|
|
17
|
+
|
|
18
|
+
@client = Faraday.new(API_BASE_URL) do |conn|
|
|
19
|
+
conn.request :json
|
|
20
|
+
conn.response :json
|
|
21
|
+
conn.adapter Faraday.default_adapter
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Generate content using Gemini API
|
|
26
|
+
#
|
|
27
|
+
# @param model [String] Model name (e.g., "gemini-2.0-flash")
|
|
28
|
+
# @param messages [Array<Hash>] Conversation messages
|
|
29
|
+
# @param tools [Array<Hash>] Available tools (optional)
|
|
30
|
+
# @param system_instruction [String] System instruction (optional)
|
|
31
|
+
# @return [Hash] API response
|
|
32
|
+
def generate_content(model:, messages:, tools: nil, system_instruction: nil)
|
|
33
|
+
url = "/v1beta/models/#{model}:generateContent"
|
|
34
|
+
|
|
35
|
+
payload = {
|
|
36
|
+
contents: format_messages(messages),
|
|
37
|
+
generationConfig: {
|
|
38
|
+
temperature: 0.7,
|
|
39
|
+
topK: 40,
|
|
40
|
+
topP: 0.95,
|
|
41
|
+
maxOutputTokens: 8192
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
payload[:systemInstruction] = { parts: [{ text: system_instruction }] } if system_instruction
|
|
46
|
+
payload[:tools] = [{ functionDeclarations: tools }] if tools && !tools.empty?
|
|
47
|
+
|
|
48
|
+
response = @client.post("#{url}?key=#{@api_key}") do |req|
|
|
49
|
+
req.body = payload
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
handle_response(response)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
# Format messages for Gemini API
|
|
58
|
+
def format_messages(messages)
|
|
59
|
+
messages.map do |msg|
|
|
60
|
+
if msg[:parts]
|
|
61
|
+
# Already formatted
|
|
62
|
+
msg
|
|
63
|
+
else
|
|
64
|
+
# Convert simple text messages
|
|
65
|
+
{
|
|
66
|
+
role: msg[:role] == "assistant" ? "model" : msg[:role],
|
|
67
|
+
parts: [{ text: msg[:content] }]
|
|
68
|
+
}
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Handle API response
|
|
74
|
+
def handle_response(response)
|
|
75
|
+
case response.status
|
|
76
|
+
when 200
|
|
77
|
+
response.body
|
|
78
|
+
when 400
|
|
79
|
+
raise Error, "Bad request: #{response.body.dig('error', 'message') || response.body}"
|
|
80
|
+
when 401
|
|
81
|
+
raise ConfigurationError, "Invalid API key"
|
|
82
|
+
when 429
|
|
83
|
+
raise Error, "Rate limit exceeded"
|
|
84
|
+
else
|
|
85
|
+
raise Error, "API error (#{response.status}): #{response.body}"
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Google
|
|
4
|
+
module ADK
|
|
5
|
+
# Configuration for context caching
|
|
6
|
+
class ContextCacheConfig
|
|
7
|
+
attr_accessor :min_tokens, :ttl_seconds, :cache_intervals
|
|
8
|
+
|
|
9
|
+
# Initialize cache configuration
|
|
10
|
+
#
|
|
11
|
+
# @param min_tokens [Integer] Minimum tokens to cache (default: 1024)
|
|
12
|
+
# @param ttl_seconds [Integer] Cache TTL in seconds (default: 300)
|
|
13
|
+
# @param cache_intervals [Array<Integer>] Cache intervals (default: [])
|
|
14
|
+
def initialize(min_tokens: 1024, ttl_seconds: 300, cache_intervals: [])
|
|
15
|
+
@min_tokens = min_tokens
|
|
16
|
+
@ttl_seconds = ttl_seconds
|
|
17
|
+
@cache_intervals = cache_intervals
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Configuration for agent run
|
|
22
|
+
class RunConfig
|
|
23
|
+
attr_accessor :max_tokens, :temperature, :context_window_compression,
|
|
24
|
+
:max_steps, :timeout_seconds
|
|
25
|
+
|
|
26
|
+
# Initialize run configuration
|
|
27
|
+
#
|
|
28
|
+
# @param max_tokens [Integer] Maximum tokens for response (optional)
|
|
29
|
+
# @param temperature [Float] LLM temperature (default: 0.7)
|
|
30
|
+
# @param context_window_compression [Boolean] Enable compression (default: false)
|
|
31
|
+
# @param max_steps [Integer] Maximum execution steps (optional)
|
|
32
|
+
# @param timeout_seconds [Integer] Execution timeout (optional)
|
|
33
|
+
def initialize(max_tokens: nil, temperature: 0.7,
|
|
34
|
+
context_window_compression: false,
|
|
35
|
+
max_steps: nil, timeout_seconds: nil)
|
|
36
|
+
@max_tokens = max_tokens
|
|
37
|
+
@temperature = temperature
|
|
38
|
+
@context_window_compression = context_window_compression
|
|
39
|
+
@max_steps = max_steps
|
|
40
|
+
@timeout_seconds = timeout_seconds
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Read-only context for accessing state
|
|
45
|
+
class ReadonlyContext
|
|
46
|
+
attr_reader :invocation_id, :agent_name, :state
|
|
47
|
+
|
|
48
|
+
# Initialize readonly context
|
|
49
|
+
#
|
|
50
|
+
# @param invocation_id [String] Unique invocation ID
|
|
51
|
+
# @param agent_name [String] Current agent name
|
|
52
|
+
# @param state [Hash] Current state (will be frozen)
|
|
53
|
+
def initialize(invocation_id:, agent_name:, state:)
|
|
54
|
+
@invocation_id = invocation_id
|
|
55
|
+
@agent_name = agent_name
|
|
56
|
+
@state = state.freeze
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Context for callbacks with mutable state
|
|
61
|
+
class CallbackContext < ReadonlyContext
|
|
62
|
+
attr_reader :session
|
|
63
|
+
|
|
64
|
+
# Initialize callback context
|
|
65
|
+
#
|
|
66
|
+
# @param invocation_id [String] Unique invocation ID
|
|
67
|
+
# @param agent_name [String] Current agent name
|
|
68
|
+
# @param session [Object] Session object with state
|
|
69
|
+
def initialize(invocation_id:, agent_name:, session:)
|
|
70
|
+
@invocation_id = invocation_id
|
|
71
|
+
@agent_name = agent_name
|
|
72
|
+
@session = session
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Get mutable state from session
|
|
76
|
+
#
|
|
77
|
+
# @return [Hash] Mutable state hash
|
|
78
|
+
def state
|
|
79
|
+
@session.state
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Update multiple state values
|
|
83
|
+
#
|
|
84
|
+
# @param updates [Hash] Key-value pairs to update
|
|
85
|
+
def update_state(updates)
|
|
86
|
+
state.merge!(updates)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Context for tool execution
|
|
91
|
+
class ToolContext < CallbackContext
|
|
92
|
+
attr_reader :auth_service, :artifact_service, :memory_service
|
|
93
|
+
|
|
94
|
+
# Initialize tool context
|
|
95
|
+
#
|
|
96
|
+
# @param invocation_id [String] Unique invocation ID
|
|
97
|
+
# @param agent_name [String] Current agent name
|
|
98
|
+
# @param session [Object] Session object
|
|
99
|
+
# @param auth_service [Object] Authentication service (optional)
|
|
100
|
+
# @param artifact_service [Object] Artifact service (optional)
|
|
101
|
+
# @param memory_service [Object] Memory service (optional)
|
|
102
|
+
def initialize(invocation_id:, agent_name:, session:,
|
|
103
|
+
auth_service: nil, artifact_service: nil, memory_service: nil)
|
|
104
|
+
super(invocation_id: invocation_id, agent_name: agent_name, session: session)
|
|
105
|
+
@auth_service = auth_service
|
|
106
|
+
@artifact_service = artifact_service
|
|
107
|
+
@memory_service = memory_service
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Request authentication
|
|
111
|
+
#
|
|
112
|
+
# @param auth_type [String] Type of authentication
|
|
113
|
+
# @param options [Hash] Authentication options
|
|
114
|
+
def request_auth(auth_type, **options)
|
|
115
|
+
raise AgentError, "Auth service not available" unless @auth_service
|
|
116
|
+
|
|
117
|
+
@auth_service.request_auth(auth_type, options)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# List artifacts
|
|
121
|
+
#
|
|
122
|
+
# @return [Array] List of artifacts
|
|
123
|
+
def list_artifacts
|
|
124
|
+
return [] unless @artifact_service
|
|
125
|
+
|
|
126
|
+
@artifact_service.list_artifacts
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Search memory
|
|
130
|
+
#
|
|
131
|
+
# @param query [String] Search query
|
|
132
|
+
# @return [Array] Search results
|
|
133
|
+
def search_memory(query)
|
|
134
|
+
return [] unless @memory_service
|
|
135
|
+
|
|
136
|
+
@memory_service.search(query)
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Full invocation context for agent execution
|
|
141
|
+
class InvocationContext
|
|
142
|
+
attr_reader :session, :agent, :invocation_id, :session_service,
|
|
143
|
+
:artifact_service, :memory_service, :agent_states,
|
|
144
|
+
:context_cache_config, :run_config
|
|
145
|
+
|
|
146
|
+
# Initialize invocation context
|
|
147
|
+
#
|
|
148
|
+
# @param session [Object] Current session
|
|
149
|
+
# @param agent [BaseAgent] Current agent
|
|
150
|
+
# @param invocation_id [String] Unique invocation ID
|
|
151
|
+
# @param session_service [Object] Session service
|
|
152
|
+
# @param artifact_service [Object] Artifact service (optional)
|
|
153
|
+
# @param memory_service [Object] Memory service (optional)
|
|
154
|
+
# @param context_cache_config [ContextCacheConfig] Cache config (optional)
|
|
155
|
+
# @param run_config [RunConfig] Run configuration (optional)
|
|
156
|
+
def initialize(session:, agent:, invocation_id:, session_service:,
|
|
157
|
+
artifact_service: nil, memory_service: nil,
|
|
158
|
+
context_cache_config: nil, run_config: nil)
|
|
159
|
+
@session = session
|
|
160
|
+
@agent = agent
|
|
161
|
+
@invocation_id = invocation_id
|
|
162
|
+
@session_service = session_service
|
|
163
|
+
@artifact_service = artifact_service
|
|
164
|
+
@memory_service = memory_service
|
|
165
|
+
@agent_states = {}
|
|
166
|
+
@context_cache_config = context_cache_config || ContextCacheConfig.new
|
|
167
|
+
@run_config = run_config || RunConfig.new
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Get agent state
|
|
171
|
+
#
|
|
172
|
+
# @param agent_name [String] Agent name
|
|
173
|
+
# @return [Hash] Agent state or empty hash
|
|
174
|
+
def get_agent_state(agent_name)
|
|
175
|
+
@agent_states[agent_name] || {}
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Update agent state
|
|
179
|
+
#
|
|
180
|
+
# @param agent_name [String] Agent name
|
|
181
|
+
# @param state [Hash] New state
|
|
182
|
+
def update_agent_state(agent_name, state)
|
|
183
|
+
@agent_states[agent_name] = state
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# Get current session state
|
|
187
|
+
#
|
|
188
|
+
# @return [Hash] Session state
|
|
189
|
+
def state
|
|
190
|
+
@session.state
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# Update session state
|
|
194
|
+
#
|
|
195
|
+
# @param updates [Hash] State updates
|
|
196
|
+
def update_state(updates)
|
|
197
|
+
@session.state.merge!(updates)
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# Add event to session
|
|
201
|
+
#
|
|
202
|
+
# @param event [Event] Event to add
|
|
203
|
+
def add_event(event)
|
|
204
|
+
@session.events << event
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# Get conversation history
|
|
208
|
+
#
|
|
209
|
+
# @return [Array<Event>] Event history
|
|
210
|
+
def events
|
|
211
|
+
@session.events
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Create callback context
|
|
215
|
+
#
|
|
216
|
+
# @return [CallbackContext] Callback context
|
|
217
|
+
def to_callback_context
|
|
218
|
+
CallbackContext.new(
|
|
219
|
+
invocation_id: @invocation_id,
|
|
220
|
+
agent_name: @agent.name,
|
|
221
|
+
session: @session
|
|
222
|
+
)
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# Create tool context
|
|
226
|
+
#
|
|
227
|
+
# @param auth_service [Object] Auth service (optional)
|
|
228
|
+
# @return [ToolContext] Tool context
|
|
229
|
+
def to_tool_context(auth_service: nil)
|
|
230
|
+
ToolContext.new(
|
|
231
|
+
invocation_id: @invocation_id,
|
|
232
|
+
agent_name: @agent.name,
|
|
233
|
+
session: @session,
|
|
234
|
+
auth_service: auth_service,
|
|
235
|
+
artifact_service: @artifact_service,
|
|
236
|
+
memory_service: @memory_service
|
|
237
|
+
)
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
end
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "securerandom"
|
|
4
|
+
require "time"
|
|
5
|
+
require "set"
|
|
6
|
+
|
|
7
|
+
module Google
|
|
8
|
+
module ADK
|
|
9
|
+
# Represents a function call in an event
|
|
10
|
+
class FunctionCall
|
|
11
|
+
attr_reader :id, :name, :arguments
|
|
12
|
+
|
|
13
|
+
# Initialize a function call
|
|
14
|
+
#
|
|
15
|
+
# @param id [String] Unique identifier for the call (optional)
|
|
16
|
+
# @param name [String] Function name
|
|
17
|
+
# @param arguments [Hash] Function arguments
|
|
18
|
+
def initialize(id: nil, name:, arguments:)
|
|
19
|
+
@id = id || "call-#{SecureRandom.uuid}"
|
|
20
|
+
@name = name
|
|
21
|
+
@arguments = arguments
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Convert to hash
|
|
25
|
+
#
|
|
26
|
+
# @return [Hash] Hash representation
|
|
27
|
+
def to_h
|
|
28
|
+
{
|
|
29
|
+
id: @id,
|
|
30
|
+
name: @name,
|
|
31
|
+
arguments: @arguments
|
|
32
|
+
}
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Represents a function response in an event
|
|
37
|
+
class FunctionResponse
|
|
38
|
+
attr_reader :id, :name, :response, :is_error
|
|
39
|
+
|
|
40
|
+
# Initialize a function response
|
|
41
|
+
#
|
|
42
|
+
# @param id [String] ID of the function call this responds to
|
|
43
|
+
# @param name [String] Function name
|
|
44
|
+
# @param response [Hash] Function response
|
|
45
|
+
# @param is_error [Boolean] Whether this is an error response
|
|
46
|
+
def initialize(id:, name:, response:, is_error: false)
|
|
47
|
+
@id = id
|
|
48
|
+
@name = name
|
|
49
|
+
@response = response
|
|
50
|
+
@is_error = is_error
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Convert to hash
|
|
54
|
+
#
|
|
55
|
+
# @return [Hash] Hash representation
|
|
56
|
+
def to_h
|
|
57
|
+
{
|
|
58
|
+
id: @id,
|
|
59
|
+
name: @name,
|
|
60
|
+
response: @response,
|
|
61
|
+
is_error: @is_error
|
|
62
|
+
}
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Manages agent actions and state changes
|
|
67
|
+
class EventActions
|
|
68
|
+
attr_accessor :state_delta, :agent_state, :artifact_delta,
|
|
69
|
+
:transfer_to_agent, :escalate, :skip_summarization,
|
|
70
|
+
:end_of_agent, :requested_auth_configs,
|
|
71
|
+
:requested_tool_confirmations, :rewind_before_invocation_id,
|
|
72
|
+
:compaction
|
|
73
|
+
|
|
74
|
+
# Initialize event actions
|
|
75
|
+
#
|
|
76
|
+
# @param state_delta [Hash] State changes (optional)
|
|
77
|
+
# @param agent_state [Hash] Agent-specific state (optional)
|
|
78
|
+
# @param artifact_delta [Hash] Artifact changes (optional)
|
|
79
|
+
# @param transfer_to_agent [String] Agent to transfer to (optional)
|
|
80
|
+
# @param escalate [Boolean] Whether to escalate to parent (optional)
|
|
81
|
+
# @param skip_summarization [Boolean] Skip LLM summarization (optional)
|
|
82
|
+
# @param end_of_agent [Boolean] End agent lifecycle (optional)
|
|
83
|
+
def initialize(state_delta: {}, agent_state: nil, artifact_delta: {},
|
|
84
|
+
transfer_to_agent: nil, escalate: false,
|
|
85
|
+
skip_summarization: false, end_of_agent: false,
|
|
86
|
+
requested_auth_configs: nil, requested_tool_confirmations: nil,
|
|
87
|
+
rewind_before_invocation_id: nil, compaction: nil)
|
|
88
|
+
@state_delta = state_delta
|
|
89
|
+
@agent_state = agent_state
|
|
90
|
+
@artifact_delta = artifact_delta
|
|
91
|
+
@transfer_to_agent = transfer_to_agent
|
|
92
|
+
@escalate = escalate
|
|
93
|
+
@skip_summarization = skip_summarization
|
|
94
|
+
@end_of_agent = end_of_agent
|
|
95
|
+
@requested_auth_configs = requested_auth_configs
|
|
96
|
+
@requested_tool_confirmations = requested_tool_confirmations
|
|
97
|
+
@rewind_before_invocation_id = rewind_before_invocation_id
|
|
98
|
+
@compaction = compaction
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Convert to hash, excluding nil and empty values
|
|
102
|
+
#
|
|
103
|
+
# @return [Hash] Hash representation
|
|
104
|
+
def to_h
|
|
105
|
+
result = {}
|
|
106
|
+
result[:state_delta] = @state_delta unless @state_delta.empty?
|
|
107
|
+
result[:agent_state] = @agent_state unless @agent_state.nil?
|
|
108
|
+
result[:artifact_delta] = @artifact_delta unless @artifact_delta.empty?
|
|
109
|
+
result[:transfer_to_agent] = @transfer_to_agent unless @transfer_to_agent.nil?
|
|
110
|
+
result[:escalate] = @escalate if @escalate
|
|
111
|
+
result[:skip_summarization] = @skip_summarization if @skip_summarization
|
|
112
|
+
result[:end_of_agent] = @end_of_agent if @end_of_agent
|
|
113
|
+
result[:requested_auth_configs] = @requested_auth_configs unless @requested_auth_configs.nil?
|
|
114
|
+
result[:requested_tool_confirmations] = @requested_tool_confirmations unless @requested_tool_confirmations.nil?
|
|
115
|
+
result[:rewind_before_invocation_id] = @rewind_before_invocation_id unless @rewind_before_invocation_id.nil?
|
|
116
|
+
result[:compaction] = @compaction unless @compaction.nil?
|
|
117
|
+
result
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Represents an event in agent-user conversation
|
|
122
|
+
class Event
|
|
123
|
+
attr_reader :id, :invocation_id, :author, :timestamp, :content,
|
|
124
|
+
:function_calls, :function_responses, :long_running_tool_ids,
|
|
125
|
+
:branch, :actions
|
|
126
|
+
|
|
127
|
+
# Initialize an event
|
|
128
|
+
#
|
|
129
|
+
# @param id [String] Unique event identifier (optional)
|
|
130
|
+
# @param invocation_id [String] Invocation ID
|
|
131
|
+
# @param author [String] Event author (user or agent name)
|
|
132
|
+
# @param timestamp [Time] Event timestamp (optional)
|
|
133
|
+
# @param content [String] Event content (optional)
|
|
134
|
+
# @param function_calls [Array<FunctionCall>] Function calls (optional)
|
|
135
|
+
# @param function_responses [Array<FunctionResponse>] Function responses (optional)
|
|
136
|
+
# @param long_running_tool_ids [Set] Long-running tool IDs (optional)
|
|
137
|
+
# @param branch [String] Conversation branch (optional)
|
|
138
|
+
# @param actions [EventActions] Event actions (optional)
|
|
139
|
+
def initialize(invocation_id:, author:, id: nil, timestamp: nil,
|
|
140
|
+
content: nil, function_calls: [], function_responses: [],
|
|
141
|
+
long_running_tool_ids: nil, branch: nil, actions: nil)
|
|
142
|
+
@id = id || self.class.new_id
|
|
143
|
+
@invocation_id = invocation_id
|
|
144
|
+
@author = author
|
|
145
|
+
@timestamp = timestamp || Time.now
|
|
146
|
+
@content = content
|
|
147
|
+
@function_calls = function_calls
|
|
148
|
+
@function_responses = function_responses
|
|
149
|
+
@long_running_tool_ids = long_running_tool_ids || Set.new
|
|
150
|
+
@branch = branch
|
|
151
|
+
@actions = actions
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Check if this is a final response
|
|
155
|
+
#
|
|
156
|
+
# @return [Boolean] True if final response
|
|
157
|
+
def is_final_response?
|
|
158
|
+
return true if @author == "user"
|
|
159
|
+
return true if @actions.nil?
|
|
160
|
+
|
|
161
|
+
@actions.transfer_to_agent.nil?
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Generate a new event ID
|
|
165
|
+
#
|
|
166
|
+
# @return [String] New UUID-based ID
|
|
167
|
+
def self.new_id
|
|
168
|
+
SecureRandom.uuid
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Convert to hash representation
|
|
172
|
+
#
|
|
173
|
+
# @return [Hash] Hash representation
|
|
174
|
+
def to_h
|
|
175
|
+
result = {
|
|
176
|
+
id: @id,
|
|
177
|
+
invocation_id: @invocation_id,
|
|
178
|
+
author: @author,
|
|
179
|
+
timestamp: @timestamp.iso8601,
|
|
180
|
+
content: @content,
|
|
181
|
+
function_calls: @function_calls.map(&:to_h),
|
|
182
|
+
function_responses: @function_responses.map(&:to_h),
|
|
183
|
+
long_running_tool_ids: @long_running_tool_ids.to_a
|
|
184
|
+
}
|
|
185
|
+
result[:branch] = @branch unless @branch.nil?
|
|
186
|
+
result[:actions] = @actions.to_h if @actions
|
|
187
|
+
result
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|