11package ai.koog.agents.ext.agent
22
33import ai.koog.agents.core.agent.entity.AIAgentStrategy
4+ import ai.koog.agents.core.agent.entity.createStorageKey
45import ai.koog.agents.core.dsl.builder.forwardTo
56import ai.koog.agents.core.dsl.builder.strategy
67import ai.koog.agents.core.dsl.extension.*
8+ import ai.koog.agents.core.environment.ReceivedToolResult
9+ import ai.koog.agents.core.environment.result
710import ai.koog.prompt.message.Message
811
912/* *
@@ -42,3 +45,107 @@ public fun chatAgentStrategy(): AIAgentStrategy<String, String> = strategy("chat
4245 edge(nodeSendToolResult forwardTo nodeFinish onToolCall { tc -> tc.tool == " __exit__" } transformed { " Chat finished" })
4346 edge(nodeSendToolResult forwardTo nodeExecuteTool onToolCall { true })
4447}
48+
49+ /* *
50+ * Creates a ReAct AI agent strategy that alternates between reasoning and execution stages
51+ * to dynamically process tasks and request outputs from an LLM.
52+ *
53+ * @param reasoningInterval Specifies the interval for reasoning steps.
54+ * @return An instance of [AIAgentStrategy] that defines the ReAct strategy.
55+ *
56+ *
57+ * +-------+ +---------------+ +---------------+ +--------+
58+ * | Start | ----------> | CallLLMReason | ----------> | CallLLMAction | ----------> | Finish |
59+ * +-------+ +---------------+ +---------------+ +--------+
60+ * ^ | Finished? Yes
61+ * | | No
62+ * | v
63+ * +-----------------------+
64+ * | ExecuteTool |
65+ * +-----------------------+
66+ *
67+ * Example execution flow of a banking agent with ReAct strategy:
68+ *
69+ * 1. Start: User asks "How much did I spend last month?"
70+ *
71+ * 2. Reasoning Phase:
72+ * CallLLMReason: "I need to follow these steps:
73+ * 1. Get all transactions from last month
74+ * 2. Filter out deposits (positive amounts)
75+ * 3. Calculate total spending"
76+ *
77+ * 3. Action & Execution Phase 1:
78+ * CallLLMAction: {tool: "get_transactions", args: {startDate: "2025-05-19", endDate: "2025-06-18"}}
79+ * ExecuteTool Result: [
80+ * {date: "2025-05-25", amount: -100.00, description: "Grocery Store"},
81+ * {date: "2025-05-31", amount: +1000.00, description: "Salary Deposit"},
82+ * {date: "2025-06-10", amount: -500.00, description: "Rent Payment"},
83+ * {date: "2025-06-13", amount: -200.00, description: "Utilities"}
84+ * ]
85+ *
86+ * 4. Reasoning Phase:
87+ * CallLLMReason: "I have the transactions. Now I need to:
88+ * 1. Remove the salary deposit of +1000.00
89+ * 2. Sum up the remaining transactions"
90+ *
91+ * 5. Action & Execution Phase 2:
92+ * CallLLMAction: {tool: "calculate_sum", args: {amounts: [-100.00, -500.00, -200.00]}}
93+ * ExecuteTool Result: -800.00
94+ *
95+ * 6. Final Response:
96+ * Assistant: "You spent $800.00 last month on groceries, rent, and utilities."
97+ *
98+ * 7. Finish: Execution complete
99+ */
100+ public fun reActStrategy (reasoningInterval : Int = 1, name : String = "re_act"): AIAgentStrategy <String , String > = strategy(name) {
101+ require(reasoningInterval > 0 ) { " Reasoning interval must be greater than 0" }
102+ val reasoningStepKey = createStorageKey<Int >(" reasoning_step" )
103+ val nodeSetup by node<String , String > {
104+ storage.set(reasoningStepKey, 0 )
105+ it
106+ }
107+ val nodeCallLLM by node<Unit , Message .Response > {
108+ llm.writeSession {
109+ requestLLM()
110+ }
111+ }
112+ val nodeExecuteTool by nodeExecuteTool()
113+
114+ val reasoningPrompt = " Please give your thoughts about the task and plan the next steps."
115+ val nodeCallLLMReasonInput by node<String , Unit > { stageInput ->
116+ llm.writeSession {
117+ updatePrompt {
118+ user(stageInput)
119+ user(reasoningPrompt)
120+ }
121+
122+ requestLLMWithoutTools()
123+ }
124+ }
125+ val nodeCallLLMReason by node<ReceivedToolResult , Unit > { result ->
126+ val reasoningStep = storage.getValue(reasoningStepKey)
127+ llm.writeSession {
128+ updatePrompt {
129+ tool {
130+ result(result)
131+ }
132+ }
133+
134+ if (reasoningStep % reasoningInterval == 0 ) {
135+ updatePrompt {
136+ user(reasoningPrompt)
137+ }
138+ requestLLMWithoutTools()
139+ }
140+ }
141+ storage.set(reasoningStepKey, reasoningStep + 1 )
142+ }
143+
144+ edge(nodeStart forwardTo nodeSetup)
145+ edge(nodeSetup forwardTo nodeCallLLMReasonInput)
146+ edge(nodeCallLLMReasonInput forwardTo nodeCallLLM)
147+ edge(nodeCallLLM forwardTo nodeExecuteTool onToolCall { true })
148+ edge(nodeCallLLM forwardTo nodeFinish onAssistantMessage { true })
149+ edge(nodeExecuteTool forwardTo nodeCallLLMReason)
150+ edge(nodeCallLLMReason forwardTo nodeCallLLM)
151+ }
0 commit comments