-
Notifications
You must be signed in to change notification settings - Fork 205
JBAI-13757. Replace EventHandler with the event-handler feature #30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
5678a01
to
bc379d4
Compare
58b3a14
to
df0f840
Compare
…andle feature - Delete EventHandler class and update its usages; - Move logic related to the feature functionality from core into features module. Restored modules dependencies; - Update logic in products and tests to use a new event-handler feature instead of an old EventHandler.
… agent from the EventHandler class - Update logic to set JSON config for remote writers in agent features to correctly process with dependencies; - Add new events from the EventHandler class; - Update all tests.
|
||
//region Trigger Agent Handlers | ||
|
||
var onAgentCreated: suspend (strategy: LocalAgentStrategy, agent: AIAgentBase) -> Unit = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that API using setters is convenient to use
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@devcrocod, could you please give some suggestions here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think using functions would be a little better
for example
private var agentStarted: suspend (strategyName: String) -> Unit =
{ strategyName: String -> }
fun onAgentStarted(block: suspend (strategyName: String) -> Unit) {
agentStarted = block
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So it's like a "glorified setter" /s? But agreed, seems like it is more idiomatic Kotlin
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@devcrocod, we also need getters here since we need to execute this block of code on a particular interceptor call (please see EventHandler#install()
). Please let me know if I miss anything.
toolRegistry: ToolRegistry? = null, | ||
maxIterations: Int = 50, | ||
): AIAgentBase { | ||
installFeatures: suspend AIAgentBase.FeatureContext.() -> Unit = {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: formatting is broken here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
} catch (e: Exception) { | ||
logger.error(e) { "Tool \"${tool.name}\" failed to run call handler with arguments: ${content.toolArgs}" } | ||
} | ||
pipeline.onToolCall(stage = stage, tool = tool, toolArgs = toolArgs) | ||
|
||
val (result, serializedResult) = try { | ||
// Tool Execution | ||
val (toolResult, serializedResult) = try { | ||
@Suppress("UNCHECKED_CAST") | ||
(tool as Tool<Tool.Args, ToolResult>).executeAndSerialize(args, toolEnabler) | ||
} catch (e: ToolException) { | ||
with(eventHandler.toolValidationFailureListener) { | ||
AgentHandlerContext(strategy.name).handle(stage, tool, args, e.message) | ||
} | ||
(tool as Tool<Tool.Args, ToolResult>).executeAndSerialize(toolArgs, toolEnabler) | ||
} | ||
catch (e: ToolException) { | ||
|
||
pipeline.onToolValidationError(stage = stage, tool = tool, toolArgs = toolArgs, error = e.message) | ||
|
||
return toolResult( | ||
message = e.message, | ||
toolCallId = content.toolCallId, | ||
toolName = content.toolName, | ||
agentId = strategy.name, | ||
result = null | ||
) | ||
} catch (e: Exception) { | ||
with(eventHandler.toolExceptionListener) { | ||
AgentHandlerContext(strategy.name).handle(stage, tool, args, e) | ||
} | ||
} | ||
catch (e: Exception) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have some concern regarding tools calls reporting. In the case of multiple tool calling we have following order of events:
- onBeforeToolCalls
- onToolCall
- onToolCallResult
- onAfterToolCalls
So, question #1 is - why do we have onBeforeToolCalls/onAfterToolCalls only for the bunch of calls, not for each. Moreover - onToolCall is called before actual call.
Second question is - do we really need that many events on each tool call, do we use it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As we discussed, I've dropped onBeforeToolCalls
and onAfterToolCalls
handlers.
class AgentFeatureClientConnectionConfig( | ||
host: String, | ||
port: Int, | ||
protocol: String = "https", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest make an enum for protocols.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or we can reuse URLProtocol from Ktor? But there are more protocols that we probably won't need, such as socks or web sockets
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed. Replaced with URLProtocol
ktor type.
@@ -23,7 +23,7 @@ import kotlin.time.Duration.Companion.seconds | |||
* @property healthCheckUrl A computed property that constructs the URL endpoint for health check requests. | |||
* @property messageUrl A computed property that constructs the URL endpoint for sending or receiving messages. | |||
*/ | |||
data class ClientConnectionConfig( | |||
abstract class ClientConnectionConfig( | |||
val host: String, | |||
val port: Int, | |||
val protocol: String = "https", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here with protocol enum
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left a few suggestions. Also, I've noticed some hardcoded dependencies that are not in libs.versions.toml. Feel free to disregard these, I just noticed this and wanted to mention it, maybe we can fix it later
) { | ||
install(EventHandlerFeature) { | ||
onToolCall = { stage, tool, arguments -> | ||
println("[DEBUG_LOG] Tool `${tool.name}` was called with arguments $arguments") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please clean up Junie logs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This log was originally in the event handler. I moved it to the new implementation. We can change it if needed outside of the current PR if you don't mind.
@@ -0,0 +1,41 @@ | |||
package ai.grazie.code.agents.core.feature.handler | |||
|
|||
class StrategyHandler<FeatureT : Any>(val feature: FeatureT) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: TFeature sounds a bit better and more aligned with standard convetions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I can rename it later, if needed. I used the same type naming as in other classes we have (AgentHandler
).
class AgentFeatureClientConnectionConfig( | ||
host: String, | ||
port: Int, | ||
protocol: String = "https", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or we can reuse URLProtocol from Ktor? But there are more protocols that we probably won't need, such as socks or web sockets
@@ -12,7 +12,6 @@ kotlin { | |||
sourceSets { | |||
commonMain { | |||
dependencies { | |||
api(project(":agents:agents-core")) | |||
api("ai.jetbrains.code.files:code-files-model:1.0.0-beta.55+0.4.45") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just noticed, shouldn't we move it to libs.versions.toml?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think yes, but let's do it outside of this PR. This dependency was here already for a while. I agree in general. Good catch! Thank you @EugeneTheDev
PR contains the following changes: