Skip to content

Commit 5ffa984

Browse files
shukladivyanshcopybara-github
authored andcommitted
feat: Add code executor
PiperOrigin-RevId: 793852596
1 parent f27f48c commit 5ffa984

File tree

9 files changed

+1325
-3
lines changed

9 files changed

+1325
-3
lines changed

core/src/main/java/com/google/adk/agents/LlmAgent.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import com.google.adk.agents.Callbacks.BeforeToolCallbackBase;
4141
import com.google.adk.agents.Callbacks.BeforeToolCallbackSync;
4242
import com.google.adk.agents.ConfigAgentUtils.ConfigurationException;
43+
import com.google.adk.codeexecutors.BaseCodeExecutor;
4344
import com.google.adk.events.Event;
4445
import com.google.adk.examples.BaseExampleProvider;
4546
import com.google.adk.examples.Example;
@@ -106,6 +107,7 @@ public enum IncludeContents {
106107
private final Optional<Schema> outputSchema;
107108
private final Optional<Executor> executor;
108109
private final Optional<String> outputKey;
110+
private final Optional<BaseCodeExecutor> codeExecutor;
109111

110112
private volatile Model resolvedModel;
111113
private final BaseLlmFlow llmFlow;
@@ -139,6 +141,7 @@ protected LlmAgent(Builder builder) {
139141
this.executor = Optional.ofNullable(builder.executor);
140142
this.outputKey = Optional.ofNullable(builder.outputKey);
141143
this.toolsUnion = builder.toolsUnion != null ? builder.toolsUnion : ImmutableList.of();
144+
this.codeExecutor = Optional.ofNullable(builder.codeExecutor);
142145

143146
this.llmFlow = determineLlmFlow();
144147

@@ -179,6 +182,7 @@ public static class Builder {
179182
private Schema outputSchema;
180183
private Executor executor;
181184
private String outputKey;
185+
private BaseCodeExecutor codeExecutor;
182186

183187
@CanIgnoreReturnValue
184188
public Builder name(String name) {
@@ -563,6 +567,12 @@ public Builder outputKey(String outputKey) {
563567
return this;
564568
}
565569

570+
@CanIgnoreReturnValue
571+
public Builder codeExecutor(BaseCodeExecutor codeExecutor) {
572+
this.codeExecutor = codeExecutor;
573+
return this;
574+
}
575+
566576
protected void validate() {
567577
this.disallowTransferToParent =
568578
this.disallowTransferToParent != null && this.disallowTransferToParent;
@@ -816,6 +826,11 @@ public Optional<String> outputKey() {
816826
return outputKey;
817827
}
818828

829+
@Nullable
830+
public BaseCodeExecutor codeExecutor() {
831+
return codeExecutor.orElse(null);
832+
}
833+
819834
public Model resolvedModel() {
820835
if (resolvedModel == null) {
821836
synchronized (this) {
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.adk.codeexecutors;
18+
19+
import com.google.adk.JsonBaseModel;
20+
import com.google.adk.agents.InvocationContext;
21+
import com.google.adk.codeexecutors.CodeExecutionUtils.CodeExecutionInput;
22+
import com.google.adk.codeexecutors.CodeExecutionUtils.CodeExecutionResult;
23+
import com.google.common.collect.ImmutableList;
24+
import java.util.List;
25+
26+
/**
27+
* Abstract base class for all code executors.
28+
*
29+
* <p>The code executor allows the agent to execute code blocks from model responses and incorporate
30+
* the execution results into the final response.
31+
*/
32+
public abstract class BaseCodeExecutor extends JsonBaseModel {
33+
/**
34+
* If true, extract and process data files from the model request and attach them to the code
35+
* executor.
36+
*
37+
* <p>Supported data file MimeTypes are [text/csv]. Default to False.
38+
*/
39+
public boolean optimizeDataFile() {
40+
return false;
41+
}
42+
43+
/** Whether the code executor is stateful. Default to False. */
44+
public boolean stateful() {
45+
return false;
46+
}
47+
48+
/**
49+
* The number of attempts to retry on consecutive code execution errors.
50+
*
51+
* <p>Default to 2.
52+
*/
53+
public int errorRetryAttempts() {
54+
return 2;
55+
}
56+
57+
/**
58+
* The list of the enclosing delimiters to identify the code blocks.
59+
*
60+
* <p>For example, the delimiter ('```python\n', '\n```') can be used to identify code blocks with
61+
* the following format:
62+
*
63+
* <p>```python
64+
*
65+
* <p>print("hello")
66+
*
67+
* <p>```
68+
*/
69+
public List<List<String>> codeBlockDelimiters() {
70+
return ImmutableList.of(
71+
ImmutableList.of("```tool_code\n", "\n```"), ImmutableList.of("```python\n", "\n```"));
72+
}
73+
74+
/** The delimiters to format the code execution result. */
75+
public List<String> executionResultDelimiters() {
76+
return ImmutableList.of("```tool_output\n", "\n```");
77+
}
78+
79+
/**
80+
* Executes code and return the code execution result.
81+
*
82+
* @param invocationContext The invocation context of the code execution.
83+
* @param codeExecutionInput The code execution input.
84+
* @return The code execution result.
85+
*/
86+
public abstract CodeExecutionResult executeCode(
87+
InvocationContext invocationContext, CodeExecutionInput codeExecutionInput);
88+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.adk.codeexecutors;
18+
19+
import com.google.adk.agents.InvocationContext;
20+
import com.google.adk.codeexecutors.CodeExecutionUtils.CodeExecutionInput;
21+
import com.google.adk.codeexecutors.CodeExecutionUtils.CodeExecutionResult;
22+
import com.google.adk.models.LlmRequest;
23+
import com.google.adk.utils.ModelNameUtils;
24+
import com.google.common.collect.ImmutableList;
25+
import com.google.genai.types.GenerateContentConfig;
26+
import com.google.genai.types.Tool;
27+
import com.google.genai.types.ToolCodeExecution;
28+
29+
/**
30+
* A code executor that uses the Model's built-in code executor.
31+
*
32+
* <p>Currently only supports Gemini 2.0+ models, but will be expanded to other models.
33+
*/
34+
public class BuiltInCodeExecutor extends BaseCodeExecutor {
35+
36+
@Override
37+
public CodeExecutionResult executeCode(
38+
InvocationContext invocationContext, CodeExecutionInput codeExecutionInput) {
39+
throw new UnsupportedOperationException(
40+
"Code execution is not supported for built-in code executor.");
41+
}
42+
43+
/** Pre-process the LLM request for Gemini 2.0+ models to use the code execution tool. */
44+
public void processLlmRequest(LlmRequest.Builder llmRequestBuilder) {
45+
LlmRequest llmRequest = llmRequestBuilder.build();
46+
if (ModelNameUtils.isGemini2Model(llmRequest.model().orElse(null))) {
47+
GenerateContentConfig.Builder configBuilder =
48+
llmRequest.config().map(c -> c.toBuilder()).orElse(GenerateContentConfig.builder());
49+
ImmutableList.Builder<Tool> toolsBuilder =
50+
ImmutableList.<Tool>builder()
51+
.addAll(configBuilder.build().tools().orElse(ImmutableList.<Tool>of()));
52+
toolsBuilder.add(Tool.builder().codeExecution(ToolCodeExecution.builder().build()).build());
53+
configBuilder.tools(toolsBuilder.build());
54+
llmRequestBuilder.config(configBuilder.build());
55+
return;
56+
}
57+
throw new IllegalArgumentException(
58+
"Gemini code execution tool is not supported for model " + llmRequest.model().orElse(""));
59+
}
60+
}

0 commit comments

Comments
 (0)