Skip to content

Conversation

sdubov
Copy link
Contributor

@sdubov sdubov commented May 12, 2025

PR contains the following changes:

  • Migrate handlers from EventHandler into AgentPipeline
  • Add the event-handler feature to features module
  • Replace usages of the EventHandler class with the new event-handle feature
  • Update the tracing feature with handling new events in an agent from the EventHandler class

@sdubov sdubov requested review from Ololoshechkin and Rizzen May 12, 2025 12:05
@sdubov sdubov added the refactoring Code improvements that enhance structure, readability, and quality without changing functionality label May 12, 2025
@sdubov sdubov self-assigned this May 12, 2025
@sdubov sdubov force-pushed the sdubov/JBAI-13757 branch from 846dacd to 8d6c469 Compare May 12, 2025 12:35
@sdubov sdubov requested review from devcrocod and removed request for Ololoshechkin May 12, 2025 12:36
@sdubov sdubov force-pushed the sdubov/JBAI-13757 branch 3 times, most recently from 5678a01 to bc379d4 Compare May 12, 2025 15:19
@sdubov sdubov force-pushed the sdubov/JBAI-13757 branch 4 times, most recently from 58b3a14 to df0f840 Compare May 12, 2025 22:00
…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.
@sdubov sdubov force-pushed the sdubov/JBAI-13757 branch from df0f840 to 329b53a Compare May 12, 2025 22:57
… 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 =
Copy link
Contributor

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

Copy link
Contributor Author

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?

Copy link
Contributor

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
}

Copy link
Contributor

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

Copy link
Contributor Author

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 = {}
Copy link
Member

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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Comment on lines -260 to +252
} 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) {
Copy link
Member

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?

Copy link
Contributor Author

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",
Copy link
Member

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.

Copy link
Contributor

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

Copy link
Contributor Author

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",
Copy link
Member

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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Copy link
Contributor

@EugeneTheDev EugeneTheDev left a 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")
Copy link
Contributor

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?

Copy link
Contributor Author

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) {
Copy link
Contributor

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

Copy link
Contributor Author

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",
Copy link
Contributor

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")
Copy link
Contributor

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?

Copy link
Contributor Author

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

@sdubov sdubov force-pushed the sdubov/JBAI-13757 branch from 7659ac6 to 6ebfa09 Compare May 13, 2025 14:18
@sdubov sdubov merged commit 48eb3a1 into main May 13, 2025
3 checks passed
@sproshev sproshev deleted the sdubov/JBAI-13757 branch May 21, 2025 17:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
refactoring Code improvements that enhance structure, readability, and quality without changing functionality
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants