-
Notifications
You must be signed in to change notification settings - Fork 208
Add parallel nodes invocation #220
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
Changes from all commits
8d0e637
859b7a6
6aae528
3a81403
16272d7
b9de38c
d4b56bb
bf6f75a
a3c5bf4
02c2b62
152fdb8
43e00a4
e028fd2
0047ebc
414ae39
a9bbeea
6bbd0cc
2808b7d
e165413
a1a5630
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ import ai.koog.agents.core.environment.AIAgentEnvironment | |
import ai.koog.agents.core.feature.AIAgentFeature | ||
import ai.koog.agents.core.feature.AIAgentPipeline | ||
import ai.koog.agents.core.tools.ToolDescriptor | ||
import ai.koog.agents.core.utils.RWLock | ||
import kotlin.uuid.ExperimentalUuidApi | ||
import kotlin.uuid.Uuid | ||
|
||
|
@@ -30,18 +31,65 @@ import kotlin.uuid.Uuid | |
* @param pipeline The AI agent pipeline responsible for coordinating AI agent execution and processing. | ||
*/ | ||
@OptIn(ExperimentalUuidApi::class) | ||
internal class AIAgentContext( | ||
public class AIAgentContext( | ||
override val environment: AIAgentEnvironment, | ||
override val agentInput: String, | ||
override val config: AIAgentConfigBase, | ||
override val llm: AIAgentLLMContext, | ||
override val stateManager: AIAgentStateManager, | ||
override val storage: AIAgentStorage, | ||
llm: AIAgentLLMContext, | ||
stateManager: AIAgentStateManager, | ||
storage: AIAgentStorage, | ||
override val sessionUuid: Uuid, | ||
override val strategyId: String, | ||
@OptIn(InternalAgentsApi::class) | ||
override val pipeline: AIAgentPipeline, | ||
) : AIAgentContextBase { | ||
|
||
/** | ||
* Mutable wrapper for AI agent context properties. | ||
*/ | ||
internal class MutableAIAgentContext( | ||
var llm: AIAgentLLMContext, | ||
var stateManager: AIAgentStateManager, | ||
var storage: AIAgentStorage, | ||
) { | ||
private val rwLock = RWLock() | ||
|
||
/** | ||
* Creates a copy of the current [MutableAIAgentContext]. | ||
* @return A new instance of [MutableAIAgentContext] with copies of all mutable properties. | ||
*/ | ||
suspend fun copy(): MutableAIAgentContext { | ||
return rwLock.withReadLock { | ||
MutableAIAgentContext(llm.copy(), stateManager.copy(), storage.copy()) | ||
} | ||
} | ||
|
||
/** | ||
* Replaces the current context with the provided context. | ||
* @param llm The LLM context to replace the current context with. | ||
* @param stateManager The state manager to replace the current context with. | ||
* @param storage The storage to replace the current context with. | ||
*/ | ||
suspend fun replace(llm: AIAgentLLMContext?, stateManager: AIAgentStateManager?, storage: AIAgentStorage?) { | ||
rwLock.withWriteLock { | ||
llm?.let { this.llm = llm } | ||
stateManager?.let { this.stateManager = stateManager } | ||
storage?.let { this.storage = storage } | ||
} | ||
} | ||
} | ||
|
||
private val mutableAIAgentContext = MutableAIAgentContext(llm, stateManager, storage) | ||
|
||
override val llm: AIAgentLLMContext | ||
get() = mutableAIAgentContext.llm | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, for all these properties there's no RW lock. Meaning, when the replace operation is in progress, it's still possible to read from these fields, potentially getting inconsistent data (although the chances are probably very low) |
||
|
||
override val storage: AIAgentStorage | ||
get() = mutableAIAgentContext.storage | ||
|
||
override val stateManager: AIAgentStateManager | ||
get() = mutableAIAgentContext.stateManager | ||
|
||
/** | ||
* A map storing features associated with the current AI agent context. | ||
* The keys represent unique identifiers for specific features, defined as [AIAgentStorageKey]. | ||
|
@@ -119,4 +167,30 @@ internal class AIAgentContext( | |
strategyId = strategyId ?: this.strategyId, | ||
pipeline = pipeline ?: @OptIn(InternalAgentsApi::class) this.pipeline, | ||
) | ||
} | ||
|
||
/** | ||
* Creates a copy of the current [AIAgentContext] with deep copies of all mutable properties. | ||
* | ||
* @return A new instance of [AIAgentContext] with copies of all mutable properties. | ||
*/ | ||
override suspend fun fork(): AIAgentContextBase = copy( | ||
llm = this.llm.copy(), | ||
storage = this.storage.copy(), | ||
stateManager = this.stateManager.copy(), | ||
) | ||
|
||
/** | ||
* Replaces the current context with the provided context. | ||
* This method is used to update the current context with values from another context, | ||
* particularly useful in scenarios like parallel node execution where contexts need to be merged. | ||
* | ||
* @param context The context to replace the current context with.]] | ||
*/ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's a potential problem with this method that might confuse someone (it confused me initially, at least). From the method signature and according to KDocs it looks like the whole context will be replaced, but in fact it's not the case and only three properties are actually replaced. |
||
override suspend fun replace(context: AIAgentContextBase) { | ||
mutableAIAgentContext.replace( | ||
context.llm, | ||
context.stateManager, | ||
context.storage | ||
) | ||
} | ||
tiginamaria marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,6 +36,26 @@ public data class AIAgentLLMContext( | |
private val clock: Clock | ||
) { | ||
|
||
/** | ||
* Creates a deep copy of this LLM context. | ||
* | ||
* @return A new instance of [AIAgentLLMContext] with deep copies of mutable properties. | ||
*/ | ||
public suspend fun copy(): AIAgentLLMContext { | ||
return rwLock.withReadLock { | ||
AIAgentLLMContext( | ||
tools.toList(), | ||
toolRegistry, | ||
prompt.copy(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's no need to unnecessary copy prompt and tools, these are already fully immutable |
||
model.copy(), | ||
promptExecutor, | ||
environment, | ||
config, | ||
clock | ||
) | ||
} | ||
} | ||
|
||
private val rwLock = RWLock() | ||
|
||
/** | ||
|
@@ -44,7 +64,8 @@ public data class AIAgentLLMContext( | |
*/ | ||
@OptIn(ExperimentalStdlibApi::class) | ||
public suspend fun <T> writeSession(block: suspend AIAgentLLMWriteSession.() -> T): T = rwLock.withWriteLock { | ||
val session = AIAgentLLMWriteSession(environment, promptExecutor, tools, toolRegistry, prompt, model, config, clock) | ||
val session = | ||
AIAgentLLMWriteSession(environment, promptExecutor, tools, toolRegistry, prompt, model, config, clock) | ||
|
||
session.use { | ||
val result = it.block() | ||
|
@@ -68,4 +89,4 @@ public data class AIAgentLLMContext( | |
|
||
session.use { block(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.
This method is not used